Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
cc4fd04019 | |||
97cea33be8 | |||
1cdcb9150b | |||
![]() |
b47b2fe23c | ||
![]() |
5e38d6e829 | ||
![]() |
009e036192 | ||
![]() |
37808419a8 | ||
![]() |
f4c3782888 | ||
![]() |
1688f85f2b | ||
![]() |
b38349274f | ||
![]() |
b8d593e351 | ||
![]() |
0f7529b26a | ||
![]() |
2a0a397afa | ||
![]() |
093bcd6204 | ||
![]() |
6601ad2d38 | ||
![]() |
578ebe2a8a | ||
![]() |
8269dbd71e | ||
![]() |
08cc0a9fcd | ||
![]() |
84f20ab683 | ||
![]() |
7497345928 | ||
![]() |
822a269f75 | ||
![]() |
0699f35b03 | ||
![]() |
3829e29a63 | ||
![]() |
52e9d30f76 | ||
![]() |
da7f00ae5d | ||
![]() |
326fca709f | ||
![]() |
e860e217a0 | ||
![]() |
bc48b5d62f | ||
![]() |
7b9c1b856b |
@ -1,37 +0,0 @@
|
|||||||
version: 2.1
|
|
||||||
|
|
||||||
executors:
|
|
||||||
aebuilder:
|
|
||||||
docker:
|
|
||||||
- image: aeternity/builder
|
|
||||||
user: builder
|
|
||||||
working_directory: ~/aebytecode
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
executor: aebuilder
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- restore_cache:
|
|
||||||
keys:
|
|
||||||
- dialyzer-cache-v1-{{ .Branch }}-{{ .Revision }}
|
|
||||||
- dialyzer-cache-v1-{{ .Branch }}-
|
|
||||||
- dialyzer-cache-v1-
|
|
||||||
- run:
|
|
||||||
name: Build
|
|
||||||
command: rebar3 compile
|
|
||||||
- run:
|
|
||||||
name: Static Analysis
|
|
||||||
command: make dialyzer
|
|
||||||
- run:
|
|
||||||
name: Eunit
|
|
||||||
command: make eunit
|
|
||||||
- run:
|
|
||||||
name: Common Tests
|
|
||||||
command: make test
|
|
||||||
- save_cache:
|
|
||||||
key: dialyzer-cache-v1-{{ .Branch }}-{{ .Revision }}
|
|
||||||
paths:
|
|
||||||
- _build/default/rebar3_20.3.8_plt
|
|
||||||
- store_artifacts:
|
|
||||||
path: _build/test/logs
|
|
15
.gitea/workflows/test.yaml
Normal file
15
.gitea/workflows/test.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
name: Gajumaru Bytecode Tests
|
||||||
|
run-name: ${{ gitea.actor }} testing Gajumaru Bytecode
|
||||||
|
on: [push, workflow_dispatch]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
runs-on: linux_amd64
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: test
|
||||||
|
run: |
|
||||||
|
. /home/act_runner/.erts/27.2.1/activate
|
||||||
|
make dialyzer
|
||||||
|
make eunit
|
20
.gitignore
vendored
20
.gitignore
vendored
@ -8,21 +8,21 @@ ebin/*.beam
|
|||||||
rel/example_project
|
rel/example_project
|
||||||
.concrete/DEV_MODE
|
.concrete/DEV_MODE
|
||||||
.rebar
|
.rebar
|
||||||
aeb_asm_scan.erl
|
gmb_asm_scan.erl
|
||||||
aeb_fate_asm_scan.erl
|
gmb_fate_asm_scan.erl
|
||||||
aeb_fate_asm_scan.xrl
|
gmb_fate_asm_scan.xrl
|
||||||
_build/
|
_build/
|
||||||
aefateasm
|
gmfateasm
|
||||||
include/aeb_fate_opcodes.hrl
|
include/gmb_fate_opcodes.hrl
|
||||||
src/aeb_fate_opcodes.erl
|
src/gmb_fate_opcodes.erl
|
||||||
src/aeb_fate_ops.erl
|
src/gmb_fate_ops.erl
|
||||||
src/aeb_fate_pp.erl
|
src/gmb_fate_pp.erl
|
||||||
*.erl~
|
*.erl~
|
||||||
*.hrl~
|
*.hrl~
|
||||||
*.aes~
|
*.aes~
|
||||||
doc
|
doc
|
||||||
cover
|
cover
|
||||||
aefate
|
gmfate
|
||||||
current_counterexample.eqc
|
current_counterexample.eqc
|
||||||
.rebar3
|
.rebar3
|
||||||
ebin
|
ebin/*.beam
|
||||||
|
1
Emakefile
Normal file
1
Emakefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"src/*", [debug_info, {i, "include/"}, {outdir, "ebin/"}]}.
|
1
LICENSE
1
LICENSE
@ -1,5 +1,6 @@
|
|||||||
ISC License
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2025, QPQ AG
|
||||||
Copyright (c) 2017, aeternity developers
|
Copyright (c) 2017, aeternity developers
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
11
Makefile
11
Makefile
@ -1,5 +1,5 @@
|
|||||||
GENERATED_SRC = src/aeb_fate_opcodes.erl src/aeb_fate_ops.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl src/aeb_fate_pp.erl
|
GENERATED_SRC = src/gmb_fate_opcodes.erl src/gmb_fate_ops.erl include/gmb_fate_opcodes.hrl src/gmb_fate_asm_scan.xrl src/gmb_fate_pp.erl
|
||||||
GENERATOR_DEPS = ebin/aeb_fate_generate_ops.beam src/aeb_fate_asm_scan.template
|
GENERATOR_DEPS = ebin/gmb_fate_generate_ops.beam src/gmb_fate_asm_scan.template
|
||||||
REBAR ?= ./rebar3
|
REBAR ?= ./rebar3
|
||||||
|
|
||||||
all: local
|
all: local
|
||||||
@ -15,7 +15,8 @@ console: local
|
|||||||
clean:
|
clean:
|
||||||
@$(REBAR) clean
|
@$(REBAR) clean
|
||||||
rm -f $(GENERATED_SRC)
|
rm -f $(GENERATED_SRC)
|
||||||
rm -f ebin/*
|
rm -f ebin/*.beam
|
||||||
|
rm -rf _build
|
||||||
|
|
||||||
dialyzer: local
|
dialyzer: local
|
||||||
@$(REBAR) as local dialyzer
|
@$(REBAR) as local dialyzer
|
||||||
@ -30,7 +31,7 @@ test: local
|
|||||||
@$(REBAR) as local eunit
|
@$(REBAR) as local eunit
|
||||||
|
|
||||||
ebin/%.beam: src/%.erl
|
ebin/%.beam: src/%.erl
|
||||||
erlc -o $(dir $@) $<
|
erlc +debug_info -o $(dir $@) $<
|
||||||
|
|
||||||
$(GENERATED_SRC): $(GENERATOR_DEPS)
|
$(GENERATED_SRC): $(GENERATOR_DEPS)
|
||||||
erl -pa ebin/ -noshell -s aeb_fate_generate_ops gen_and_halt src/ include/
|
erl -pa ebin/ -noshell -s gmb_fate_generate_ops gen_and_halt src/ include/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# aebytecode
|
# gmbytecode
|
||||||
A library and stand alone assembler for aeternity bytecode.
|
A library and stand alone assembler for Gajumaru bytecode.
|
||||||
|
|
||||||
This version supports AEVM bytecode and FATE bytecode.
|
This version supports AEVM bytecode and FATE bytecode.
|
||||||
|
|
||||||
|
16
ebin/gmbytecode.app
Normal file
16
ebin/gmbytecode.app
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{application,gmbytecode,
|
||||||
|
[{description,"Bytecode definitions, serialization and deserialization for the Gajumaru."},
|
||||||
|
{vsn,"3.4.1"},
|
||||||
|
{registered,[]},
|
||||||
|
{applications,[kernel,stdlib,eblake2,gmserialization,getopt]},
|
||||||
|
{env,[]},
|
||||||
|
{modules,[gmb_aevm_abi,gmb_aevm_data,gmb_asm,gmb_asm_scan,
|
||||||
|
gmb_disassemble,gmb_fate_abi,gmb_fate_asm,
|
||||||
|
gmb_fate_asm_scan,gmb_fate_code,gmb_fate_data,
|
||||||
|
gmb_fate_encoding,gmb_fate_generate_docs,
|
||||||
|
gmb_fate_generate_ops,gmb_fate_maps,gmb_fate_opcodes,
|
||||||
|
gmb_fate_ops,gmb_fate_pp,gmb_heap,gmb_memory,
|
||||||
|
gmb_opcodes,gmb_primops,gmfateasm]},
|
||||||
|
{maintainers,[]},
|
||||||
|
{licenses,[]},
|
||||||
|
{links,[]}]}.
|
@ -88,7 +88,7 @@
|
|||||||
-define(FATE_VARIANT(Arity, Tag,T), {variant, Arity, Tag, T}).
|
-define(FATE_VARIANT(Arity, Tag,T), {variant, Arity, Tag, T}).
|
||||||
-define(FATE_CONTRACT_BYTEARRAY(B), {contract_bytearray, B}).
|
-define(FATE_CONTRACT_BYTEARRAY(B), {contract_bytearray, B}).
|
||||||
|
|
||||||
% Result of aeb_fate_code:symbol_identifier(<<"init">>).
|
% Result of gmb_fate_code:symbol_identifier(<<"init">>).
|
||||||
% Stored here to avoid repeated calls to eblake2
|
% Stored here to avoid repeated calls to eblake2
|
||||||
-define(FATE_INIT_ID, <<68,214,68,31>>).
|
-define(FATE_INIT_ID, <<68,214,68,31>>).
|
||||||
|
|
@ -1,15 +1,15 @@
|
|||||||
|
|
||||||
-record(pmap, {key_t :: aeb_aevm_data:type(),
|
-record(pmap, {key_t :: gmb_aevm_data:type(),
|
||||||
val_t :: aeb_aevm_data:type(),
|
val_t :: gmb_aevm_data:type(),
|
||||||
parent :: none | non_neg_integer(),
|
parent :: none | non_neg_integer(),
|
||||||
size = 0 :: non_neg_integer(),
|
size = 0 :: non_neg_integer(),
|
||||||
data :: #{aeb_heap:binary_value() => aeb_heap:binary_value() | tombstone}
|
data :: #{gmb_heap:binary_value() => gmb_heap:binary_value() | tombstone}
|
||||||
| stored}).
|
| stored}).
|
||||||
|
|
||||||
-record(maps, { maps = #{} :: #{ non_neg_integer() => #pmap{} }
|
-record(maps, { maps = #{} :: #{ non_neg_integer() => #pmap{} }
|
||||||
, next_id = 0 :: non_neg_integer() }).
|
, next_id = 0 :: non_neg_integer() }).
|
||||||
|
|
||||||
-record(heap, { maps :: #maps{},
|
-record(heap, { maps :: #maps{},
|
||||||
offset :: aeb_heap:offset(),
|
offset :: gmb_heap:offset(),
|
||||||
heap :: binary() | #{non_neg_integer() => non_neg_integer()} }).
|
heap :: binary() | #{non_neg_integer() => non_neg_integer()} }).
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
-define(Type(), aeb_aevm_data:type()).
|
-define(Type(), gmb_aevm_data:type()).
|
||||||
|
|
||||||
-define(TYPEREP_WORD_TAG, 0).
|
-define(TYPEREP_WORD_TAG, 0).
|
||||||
-define(TYPEREP_STRING_TAG, 1).
|
-define(TYPEREP_STRING_TAG, 1).
|
@ -1,14 +1,14 @@
|
|||||||
%%% @author Thomas Arts
|
%%% @author Thomas Arts
|
||||||
%%% @doc Allow to run QuickCheck tests as eunit tests
|
%%% @doc Allow to run QuickCheck tests as eunit tests
|
||||||
%%% `rebar3 as eqc eunit --cover`
|
%%% `rebar3 as eqc eunit --cover`
|
||||||
%%% or `rebar3 as eqc eunit --module=aeb_fate_code`
|
%%% or `rebar3 as eqc eunit --module=gmb_fate_code`
|
||||||
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
-module(aeb_fate_code_tests).
|
-module(gmb_fate_code_tests).
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
quickcheck_test_() ->
|
quickcheck_test_() ->
|
||||||
{setup, fun() -> eqc:start() end,
|
{setup, fun() -> eqc:start() end,
|
||||||
[ ?EQC_EUNIT(aefate_code_eqc, prop_opcodes, 200),
|
[ ?EQC_EUNIT(gmfate_code_eqc, prop_opcodes, 200),
|
||||||
?EQC_EUNIT(aefate_code_eqc, prop_serializes, 3000),
|
?EQC_EUNIT(gmfate_code_eqc, prop_serializes, 3000),
|
||||||
?EQC_EUNIT(aefate_code_eqc, prop_fail_serializes, 3000),
|
?EQC_EUNIT(gmfate_code_eqc, prop_fail_serializes, 3000),
|
||||||
?EQC_EUNIT(aefate_code_eqc, prop_fuzz, 3000)
|
?EQC_EUNIT(gmfate_code_eqc, prop_fuzz, 3000)
|
||||||
]}.
|
]}.
|
@ -1,14 +1,14 @@
|
|||||||
%%% @author Thomas Arts
|
%%% @author Thomas Arts
|
||||||
%%% @doc Allow to run QuickCheck tests as eunit tests
|
%%% @doc Allow to run QuickCheck tests as eunit tests
|
||||||
%%% `rebar3 as eqc eunit --cover`
|
%%% `rebar3 as eqc eunit --cover`
|
||||||
%%% or `rebar3 as eqc eunit --module=aeb_fate_data`
|
%%% or `rebar3 as eqc eunit --module=gmb_fate_data`
|
||||||
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
-module(aeb_fate_data_tests).
|
-module(gmb_fate_data_tests).
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
quickcheck_test_() ->
|
quickcheck_test_() ->
|
||||||
{setup, fun() -> eqc:start() end,
|
{setup, fun() -> eqc:start() end,
|
||||||
[ ?EQC_EUNIT(aefate_eqc, prop_roundtrip, 500),
|
[ ?EQC_EUNIT(gmfate_eqc, prop_roundtrip, 500),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_format_scan, 2000),
|
?EQC_EUNIT(gmfate_eqc, prop_format_scan, 2000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_order, 2000),
|
?EQC_EUNIT(gmfate_eqc, prop_order, 2000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_fuzz, 2000)
|
?EQC_EUNIT(gmfate_eqc, prop_fuzz, 2000)
|
||||||
]}.
|
]}.
|
@ -1,14 +1,14 @@
|
|||||||
%%% @author Thomas Arts
|
%%% @author Thomas Arts
|
||||||
%%% @doc Allow to run QuickCheck tests as eunit tests
|
%%% @doc Allow to run QuickCheck tests as eunit tests
|
||||||
%%% `rebar3 as eqc eunit --cover`
|
%%% `rebar3 as eqc eunit --cover`
|
||||||
%%% or `rebar3 as eqc eunit --module=aeb_fate_encoding`
|
%%% or `rebar3 as eqc eunit --module=gmb_fate_encoding`
|
||||||
%%% Note that for obtaining cover file, one needs `rebar3 as eqc cover
|
%%% Note that for obtaining cover file, one needs `rebar3 as eqc cover
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts
|
%%% Created : 13 Dec 2018 by Thomas Arts
|
||||||
|
|
||||||
-module(aeb_fate_encoding_tests).
|
-module(gmb_fate_encoding_tests).
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
quickcheck_test_() ->
|
quickcheck_test_() ->
|
||||||
{setup, fun() -> eqc:start() end,
|
{setup, fun() -> eqc:start() end,
|
||||||
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
|
[ ?EQC_EUNIT(gmfate_type_eqc, prop_roundtrip, 1000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
|
?EQC_EUNIT(gmfate_eqc, prop_serializes, 1000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_no_maps_in_keys, 1000),
|
?EQC_EUNIT(gmfate_eqc, prop_no_maps_in_keys, 1000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
|
?EQC_EUNIT(gmfate_eqc, prop_idempotent, 1000)
|
||||||
]}.
|
]}.
|
@ -16,7 +16,7 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
-module(aefate_code_eqc).
|
-module(gmfate_code_eqc).
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
|
||||||
@ -28,10 +28,10 @@ prop_serializes() ->
|
|||||||
in_parallel(
|
in_parallel(
|
||||||
?FORALL(FateCode, fate_code(0),
|
?FORALL(FateCode, fate_code(0),
|
||||||
begin
|
begin
|
||||||
{T0, Binary} = timer:tc(fun() -> aeb_fate_code:serialize(FateCode) end),
|
{T0, Binary} = timer:tc(fun() -> gmb_fate_code:serialize(FateCode) end),
|
||||||
?WHENFAIL(eqc:format("serialized:\n ~120p~n", [Binary]),
|
?WHENFAIL(eqc:format("serialized:\n ~120p~n", [Binary]),
|
||||||
begin
|
begin
|
||||||
{T1, Decoded} = timer:tc(fun() -> aeb_fate_code:deserialize(Binary) end),
|
{T1, Decoded} = timer:tc(fun() -> gmb_fate_code:deserialize(Binary) end),
|
||||||
measure(binary_size, size(Binary),
|
measure(binary_size, size(Binary),
|
||||||
measure(serialize, T0 / 1000,
|
measure(serialize, T0 / 1000,
|
||||||
measure(deserialize, T1 / 1000,
|
measure(deserialize, T1 / 1000,
|
||||||
@ -44,20 +44,20 @@ prop_serializes() ->
|
|||||||
prop_fail_serializes() ->
|
prop_fail_serializes() ->
|
||||||
conjunction([{Failure, eqc:counterexample(
|
conjunction([{Failure, eqc:counterexample(
|
||||||
?FORALL(FateCode, fate_code(Failure),
|
?FORALL(FateCode, fate_code(Failure),
|
||||||
?FORALL(Binary, catch aeb_fate_code:serialize(FateCode),
|
?FORALL(Binary, catch gmb_fate_code:serialize(FateCode),
|
||||||
is_binary(Binary))))
|
is_binary(Binary))))
|
||||||
=/= true} || Failure <- [1, 2, 3, 4, 5] ]).
|
=/= true} || Failure <- [1, 2, 3, 4, 5] ]).
|
||||||
|
|
||||||
prop_fuzz() ->
|
prop_fuzz() ->
|
||||||
in_parallel(
|
in_parallel(
|
||||||
?FORALL(Binary, ?LET(FateCode, fate_code(0), aeb_fate_code:serialize(FateCode)),
|
?FORALL(Binary, ?LET(FateCode, fate_code(0), gmb_fate_code:serialize(FateCode)),
|
||||||
?FORALL(FuzzedBin, fuzz(Binary),
|
?FORALL(FuzzedBin, fuzz(Binary),
|
||||||
try aeb_fate_code:deserialize(FuzzedBin) of
|
try gmb_fate_code:deserialize(FuzzedBin) of
|
||||||
Code ->
|
Code ->
|
||||||
?WHENFAIL(eqc:format("Code:\n ~p\n", [Code]),
|
?WHENFAIL(eqc:format("Code:\n ~p\n", [Code]),
|
||||||
begin
|
begin
|
||||||
Bin1 = aeb_fate_code:serialize(Code),
|
Bin1 = gmb_fate_code:serialize(Code),
|
||||||
Code1 = aeb_fate_code:deserialize(Bin1),
|
Code1 = gmb_fate_code:deserialize(Bin1),
|
||||||
?WHENFAIL(eqc:format("Reserialized\n ~120p\n", [Bin1]),
|
?WHENFAIL(eqc:format("Reserialized\n ~120p\n", [Bin1]),
|
||||||
equals(Code, Code1))
|
equals(Code, Code1))
|
||||||
end)
|
end)
|
||||||
@ -66,10 +66,10 @@ prop_fuzz() ->
|
|||||||
|
|
||||||
prop_opcodes() ->
|
prop_opcodes() ->
|
||||||
?FORALL(Opcode, choose(0, 16#ff),
|
?FORALL(Opcode, choose(0, 16#ff),
|
||||||
try M = aeb_fate_opcodes:mnemonic(Opcode),
|
try M = gmb_fate_opcodes:mnemonic(Opcode),
|
||||||
?WHENFAIL(eqc:format("opcode ~p -> ~p", [Opcode, M]),
|
?WHENFAIL(eqc:format("opcode ~p -> ~p", [Opcode, M]),
|
||||||
conjunction([{valid, lists:member(Opcode, valid_opcodes())},
|
conjunction([{valid, lists:member(Opcode, valid_opcodes())},
|
||||||
{eq, equals(aeb_fate_opcodes:m_to_op(M), Opcode)}]))
|
{eq, equals(gmb_fate_opcodes:m_to_op(M), Opcode)}]))
|
||||||
catch
|
catch
|
||||||
_:_ ->
|
_:_ ->
|
||||||
not lists:member(Opcode, valid_opcodes())
|
not lists:member(Opcode, valid_opcodes())
|
||||||
@ -77,7 +77,7 @@ prop_opcodes() ->
|
|||||||
|
|
||||||
|
|
||||||
valid_opcodes() ->
|
valid_opcodes() ->
|
||||||
[ Op || #{opcode := Op} <- aeb_fate_generate_ops:get_ops() ].
|
[ Op || #{opcode := Op} <- gmb_fate_generate_ops:get_ops() ].
|
||||||
|
|
||||||
|
|
||||||
fate_code(Failure) ->
|
fate_code(Failure) ->
|
||||||
@ -86,13 +86,13 @@ fate_code(Failure) ->
|
|||||||
{non_empty(map(if Failure == 1 -> binary(1);
|
{non_empty(map(if Failure == 1 -> binary(1);
|
||||||
true -> binary(4) end,
|
true -> binary(4) end,
|
||||||
{sublist(lists:sort([private, payable])), %% deserialize sorts them
|
{sublist(lists:sort([private, payable])), %% deserialize sorts them
|
||||||
{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
{list(gmfate_type_eqc:fate_type(Size div 3)), gmfate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
||||||
small_map(small_fate_data_key(5), small_fate_data(4)),
|
small_map(small_fate_data_key(5), small_fate_data(4)),
|
||||||
small_map(small_fate_data_key(5), small_fate_data(4))},
|
small_map(small_fate_data_key(5), small_fate_data(4))},
|
||||||
aeb_fate_code:update_annotations(
|
gmb_fate_code:update_annotations(
|
||||||
aeb_fate_code:update_symbols(
|
gmb_fate_code:update_symbols(
|
||||||
aeb_fate_code:update_functions(
|
gmb_fate_code:update_functions(
|
||||||
aeb_fate_code:new(), FMap), SMap), AMap))).
|
gmb_fate_code:new(), FMap), SMap), AMap))).
|
||||||
|
|
||||||
short_list(Max, Gen) ->
|
short_list(Max, Gen) ->
|
||||||
?LET(N, choose(0, Max), eqc_gen:list(N, Gen)).
|
?LET(N, choose(0, Max), eqc_gen:list(N, Gen)).
|
||||||
@ -108,7 +108,7 @@ bbs_code(Failure) ->
|
|||||||
lists:zip(lists:seq(0, length(BBs)-1), BBs)))}]).
|
lists:zip(lists:seq(0, length(BBs)-1), BBs)))}]).
|
||||||
|
|
||||||
bb_code(Failure) ->
|
bb_code(Failure) ->
|
||||||
EndBB = [ Op || Op <- valid_opcodes(), aeb_fate_opcodes:end_bb(Op) ],
|
EndBB = [ Op || Op <- valid_opcodes(), gmb_fate_opcodes:end_bb(Op) ],
|
||||||
NonEndBB = valid_opcodes() -- EndBB,
|
NonEndBB = valid_opcodes() -- EndBB,
|
||||||
frequency(
|
frequency(
|
||||||
[{if Failure == 3 -> 5; true -> 0 end, ?LET(Ops, non_empty(short_list(6, elements(NonEndBB))), bblock(Failure, Ops))},
|
[{if Failure == 3 -> 5; true -> 0 end, ?LET(Ops, non_empty(short_list(6, elements(NonEndBB))), bblock(Failure, Ops))},
|
||||||
@ -118,8 +118,8 @@ bb_code(Failure) ->
|
|||||||
|
|
||||||
bblock(Failure, Ops) ->
|
bblock(Failure, Ops) ->
|
||||||
[ begin
|
[ begin
|
||||||
Mnemonic = aeb_fate_opcodes:mnemonic(Op),
|
Mnemonic = gmb_fate_opcodes:mnemonic(Op),
|
||||||
Arity = aeb_fate_opcodes:args(Op),
|
Arity = gmb_fate_opcodes:args(Op),
|
||||||
case Arity of
|
case Arity of
|
||||||
0 -> Mnemonic;
|
0 -> Mnemonic;
|
||||||
_ -> list_to_tuple([Mnemonic |
|
_ -> list_to_tuple([Mnemonic |
|
||||||
@ -143,7 +143,7 @@ fuzz(Binary) ->
|
|||||||
prop_small() ->
|
prop_small() ->
|
||||||
?FORALL(Value, small_fate_data(4),
|
?FORALL(Value, small_fate_data(4),
|
||||||
begin
|
begin
|
||||||
Bin = aeb_fate_encoding:serialize(Value),
|
Bin = gmb_fate_encoding:serialize(Value),
|
||||||
Size = byte_size(Bin),
|
Size = byte_size(Bin),
|
||||||
measure(size, Size,
|
measure(size, Size,
|
||||||
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
||||||
@ -151,9 +151,9 @@ prop_small() ->
|
|||||||
end).
|
end).
|
||||||
|
|
||||||
prop_small_type() ->
|
prop_small_type() ->
|
||||||
?FORALL(Type, ?SIZED(Size, aefate_type_eqc:fate_type(Size div 3)),
|
?FORALL(Type, ?SIZED(Size, gmfate_type_eqc:fate_type(Size div 3)),
|
||||||
begin
|
begin
|
||||||
Bin = iolist_to_binary(aeb_fate_encoding:serialize_type(Type)),
|
Bin = iolist_to_binary(gmb_fate_encoding:serialize_type(Type)),
|
||||||
Size = byte_size(Bin),
|
Size = byte_size(Bin),
|
||||||
measure(size, Size,
|
measure(size, Size,
|
||||||
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
||||||
@ -161,7 +161,7 @@ prop_small_type() ->
|
|||||||
end).
|
end).
|
||||||
|
|
||||||
small_fate_data(N) ->
|
small_fate_data(N) ->
|
||||||
?SIZED(Size, resize(Size div N, aefate_eqc:fate_data())).
|
?SIZED(Size, resize(Size div N, gmfate_eqc:fate_data())).
|
||||||
|
|
||||||
small_fate_data_key(N) ->
|
small_fate_data_key(N) ->
|
||||||
?SIZED(Size, ?LET(Data, aefate_eqc:fate_data(Size div N, []), eqc_symbolic:eval(Data))).
|
?SIZED(Size, ?LET(Data, gmfate_eqc:fate_data(Size div N, []), eqc_symbolic:eval(Data))).
|
@ -7,10 +7,10 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
-module(aefate_eqc).
|
-module(gmfate_eqc).
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
-include("../include/aeb_fate_data.hrl").
|
-include("../include/gmb_fate_data.hrl").
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
@ -18,17 +18,17 @@ prop_roundtrip() ->
|
|||||||
?FORALL(FateData, fate_data(),
|
?FORALL(FateData, fate_data(),
|
||||||
measure(bytes, size(term_to_binary(FateData)),
|
measure(bytes, size(term_to_binary(FateData)),
|
||||||
begin
|
begin
|
||||||
Serialized = aeb_fate_encoding:serialize(FateData),
|
Serialized = gmb_fate_encoding:serialize(FateData),
|
||||||
?WHENFAIL(eqc:format("Serialized ~p to ~p~n", [FateData, Serialized]),
|
?WHENFAIL(eqc:format("Serialized ~p to ~p~n", [FateData, Serialized]),
|
||||||
equals(aeb_fate_encoding:deserialize(Serialized), FateData))
|
equals(gmb_fate_encoding:deserialize(Serialized), FateData))
|
||||||
end)).
|
end)).
|
||||||
|
|
||||||
prop_format_scan() ->
|
prop_format_scan() ->
|
||||||
?FORALL(FateData, fate_data([variant, map]),
|
?FORALL(FateData, fate_data([variant, map]),
|
||||||
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
||||||
begin
|
begin
|
||||||
String = aeb_fate_data:format(FateData),
|
String = gmb_fate_data:format(FateData),
|
||||||
{ok, _Scanned, _} = aeb_fate_asm_scan:scan(unicode:characters_to_list(String)),
|
{ok, _Scanned, _} = gmb_fate_asm_scan:scan(unicode:characters_to_list(String)),
|
||||||
true
|
true
|
||||||
end)).
|
end)).
|
||||||
|
|
||||||
@ -36,8 +36,8 @@ prop_serializes() ->
|
|||||||
?FORALL({Data, Garbage}, {fate_data(), binary()},
|
?FORALL({Data, Garbage}, {fate_data(), binary()},
|
||||||
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [Data]),
|
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [Data]),
|
||||||
begin
|
begin
|
||||||
Binary = <<(aeb_fate_encoding:serialize(Data))/binary, Garbage/binary>>,
|
Binary = <<(gmb_fate_encoding:serialize(Data))/binary, Garbage/binary>>,
|
||||||
{FateData, Rest} = aeb_fate_encoding:deserialize_one(Binary),
|
{FateData, Rest} = gmb_fate_encoding:deserialize_one(Binary),
|
||||||
measure(binary_size, size(Binary),
|
measure(binary_size, size(Binary),
|
||||||
conjunction([{equal, equals(Data, FateData)},
|
conjunction([{equal, equals(Data, FateData)},
|
||||||
{rest, equals(Garbage, Rest)},
|
{rest, equals(Garbage, Rest)},
|
||||||
@ -48,7 +48,7 @@ prop_no_maps_in_keys() ->
|
|||||||
?FORALL(FateData, fate_bad_map(), %% may contain a map in its keys
|
?FORALL(FateData, fate_bad_map(), %% may contain a map in its keys
|
||||||
begin
|
begin
|
||||||
HasMapInKeys = lists:any(fun(K) -> has_map(K) end, maps:keys(FateData)),
|
HasMapInKeys = lists:any(fun(K) -> has_map(K) end, maps:keys(FateData)),
|
||||||
try aeb_fate_encoding:serialize(FateData),
|
try gmb_fate_encoding:serialize(FateData),
|
||||||
?WHENFAIL(eqc:format("Should not serialize, contains a map in key\n", []),
|
?WHENFAIL(eqc:format("Should not serialize, contains a map in key\n", []),
|
||||||
not HasMapInKeys)
|
not HasMapInKeys)
|
||||||
catch error:Reason ->
|
catch error:Reason ->
|
||||||
@ -58,11 +58,11 @@ prop_no_maps_in_keys() ->
|
|||||||
|
|
||||||
prop_fuzz() ->
|
prop_fuzz() ->
|
||||||
in_parallel(
|
in_parallel(
|
||||||
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), aeb_fate_encoding:serialize(FateData)),
|
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), gmb_fate_encoding:serialize(FateData)),
|
||||||
?FORALL(InjectedBin, injection(Binary),
|
?FORALL(InjectedBin, injection(Binary),
|
||||||
try Org = aeb_fate_encoding:deserialize(InjectedBin),
|
try Org = gmb_fate_encoding:deserialize(InjectedBin),
|
||||||
NewBin = aeb_fate_encoding:serialize(Org),
|
NewBin = gmb_fate_encoding:serialize(Org),
|
||||||
NewOrg = aeb_fate_encoding:deserialize(NewBin),
|
NewOrg = gmb_fate_encoding:deserialize(NewBin),
|
||||||
measure(success, 1,
|
measure(success, 1,
|
||||||
?WHENFAIL(eqc:format("Deserialize ~p gives\n~p\nSerializes to ~p\n", [InjectedBin, Org, NewOrg]),
|
?WHENFAIL(eqc:format("Deserialize ~p gives\n~p\nSerializes to ~p\n", [InjectedBin, Org, NewOrg]),
|
||||||
equals(NewBin, InjectedBin)))
|
equals(NewBin, InjectedBin)))
|
||||||
@ -77,20 +77,20 @@ prop_order() ->
|
|||||||
%% Use lt to take minimum
|
%% Use lt to take minimum
|
||||||
Min = lt_min(Items),
|
Min = lt_min(Items),
|
||||||
Max = lt_max(Items),
|
Max = lt_max(Items),
|
||||||
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
|
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, gmb_fate_data:lt(I, Min)])},
|
||||||
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])},
|
{maximum, is_empty([ {Max, '<', I} || I<-Items, gmb_fate_data:lt(Max, I)])},
|
||||||
{asym, aeb_fate_data:lt(Min, Max) orelse Min == Max}])
|
{asym, gmb_fate_data:lt(Min, Max) orelse Min == Max}])
|
||||||
end).
|
end).
|
||||||
|
|
||||||
lt_min([X, Y | Rest]) ->
|
lt_min([X, Y | Rest]) ->
|
||||||
case aeb_fate_data:lt(X, Y) of
|
case gmb_fate_data:lt(X, Y) of
|
||||||
true -> lt_min([X | Rest]);
|
true -> lt_min([X | Rest]);
|
||||||
false -> lt_min([Y| Rest])
|
false -> lt_min([Y| Rest])
|
||||||
end;
|
end;
|
||||||
lt_min([X]) -> X.
|
lt_min([X]) -> X.
|
||||||
|
|
||||||
lt_max([X, Y | Rest]) ->
|
lt_max([X, Y | Rest]) ->
|
||||||
case aeb_fate_data:lt(X, Y) of
|
case gmb_fate_data:lt(X, Y) of
|
||||||
true -> lt_max([Y | Rest]);
|
true -> lt_max([Y | Rest]);
|
||||||
false -> lt_max([X| Rest])
|
false -> lt_max([X| Rest])
|
||||||
end;
|
end;
|
||||||
@ -98,8 +98,8 @@ lt_max([X]) -> X.
|
|||||||
|
|
||||||
prop_idempotent() ->
|
prop_idempotent() ->
|
||||||
?FORALL(Items, list({fate_data_key(), fate_data()}),
|
?FORALL(Items, list({fate_data_key(), fate_data()}),
|
||||||
equals(aeb_fate_encoding:sort(Items),
|
equals(gmb_fate_encoding:sort(Items),
|
||||||
aeb_fate_encoding:sort(aeb_fate_encoding:sort(Items)))).
|
gmb_fate_encoding:sort(gmb_fate_encoding:sort(Items)))).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -131,20 +131,20 @@ fate_data(Size, Options) ->
|
|||||||
|| lists:member(map, Options)])).
|
|| lists:member(map, Options)])).
|
||||||
|
|
||||||
|
|
||||||
fate_integer() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_integer(X))).
|
fate_integer() -> ?LET(X, oneof([int(), largeint()]), return(gmb_fate_data:make_integer(X))).
|
||||||
fate_bits() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_bits(X))).
|
fate_bits() -> ?LET(X, oneof([int(), largeint()]), return(gmb_fate_data:make_bits(X))).
|
||||||
fate_boolean() -> ?LET(X, elements([true, false]), return(aeb_fate_data:make_boolean(X))).
|
fate_boolean() -> ?LET(X, elements([true, false]), return(gmb_fate_data:make_boolean(X))).
|
||||||
fate_nil() -> aeb_fate_data:make_list([]).
|
fate_nil() -> gmb_fate_data:make_list([]).
|
||||||
fate_unit() -> aeb_fate_data:make_unit().
|
fate_unit() -> gmb_fate_data:make_unit().
|
||||||
fate_string() -> ?LET(X, frequency([{10, non_quote_string()}, {2, list(non_quote_string())},
|
fate_string() -> ?LET(X, frequency([{10, non_quote_string()}, {2, list(non_quote_string())},
|
||||||
{1, ?LET(N, choose(64-3, 64+3), vector(N, $a))}]),
|
{1, ?LET(N, choose(64-3, 64+3), vector(N, $a))}]),
|
||||||
return(aeb_fate_data:make_string(X))).
|
return(gmb_fate_data:make_string(X))).
|
||||||
fate_address() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_address(X))).
|
fate_address() -> ?LET(X, binary(256 div 8), return(gmb_fate_data:make_address(X))).
|
||||||
fate_bytes() -> ?LET(X, non_empty(binary()), return(aeb_fate_data:make_bytes(X))).
|
fate_bytes() -> ?LET(X, non_empty(binary()), return(gmb_fate_data:make_bytes(X))).
|
||||||
fate_contract() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_contract(X))).
|
fate_contract() -> ?LET(X, binary(256 div 8), return(gmb_fate_data:make_contract(X))).
|
||||||
fate_oracle() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle(X))).
|
fate_oracle() -> ?LET(X, binary(256 div 8), return(gmb_fate_data:make_oracle(X))).
|
||||||
fate_oracle_q() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle_query(X))).
|
fate_oracle_q() -> ?LET(X, binary(256 div 8), return(gmb_fate_data:make_oracle_query(X))).
|
||||||
fate_channel() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_channel(X))).
|
fate_channel() -> ?LET(X, binary(256 div 8), return(gmb_fate_data:make_channel(X))).
|
||||||
|
|
||||||
fate_values(Size, N, Options) ->
|
fate_values(Size, N, Options) ->
|
||||||
eqc_gen:list(N, fate_data(Size div max(1, N), Options)).
|
eqc_gen:list(N, fate_data(Size div max(1, N), Options)).
|
||||||
@ -153,34 +153,34 @@ fate_values(Size, N, Options) ->
|
|||||||
fate_tuple(Size, Options) ->
|
fate_tuple(Size, Options) ->
|
||||||
?LET(N, choose(0, 6),
|
?LET(N, choose(0, 6),
|
||||||
?LETSHRINK(Elements, fate_values(Size, N, Options),
|
?LETSHRINK(Elements, fate_values(Size, N, Options),
|
||||||
return(aeb_fate_data:make_tuple(list_to_tuple(Elements))))).
|
return(gmb_fate_data:make_tuple(list_to_tuple(Elements))))).
|
||||||
|
|
||||||
fate_variant(Size, Options) ->
|
fate_variant(Size, Options) ->
|
||||||
?LET({L1, L2, {tuple, Args}}, {list(choose(0, 255)), list(choose(0,255)), fate_tuple(Size, Options)},
|
?LET({L1, L2, {tuple, Args}}, {list(choose(0, 255)), list(choose(0,255)), fate_tuple(Size, Options)},
|
||||||
return(aeb_fate_data:make_variant(L1 ++ [tuple_size(Args)] ++ L2,
|
return(gmb_fate_data:make_variant(L1 ++ [tuple_size(Args)] ++ L2,
|
||||||
length(L1), Args))).
|
length(L1), Args))).
|
||||||
|
|
||||||
fate_list(Size, Options) ->
|
fate_list(Size, Options) ->
|
||||||
?LET(N, frequency([{20, choose(0, 6)}, {1, choose(64 - 3, 64 + 3)}]),
|
?LET(N, frequency([{20, choose(0, 6)}, {1, choose(64 - 3, 64 + 3)}]),
|
||||||
?LETSHRINK(Vs, fate_values(Size, N, Options),
|
?LETSHRINK(Vs, fate_values(Size, N, Options),
|
||||||
return(aeb_fate_data:make_list(Vs)))).
|
return(gmb_fate_data:make_list(Vs)))).
|
||||||
|
|
||||||
fate_map(Size, Options) ->
|
fate_map(Size, Options) ->
|
||||||
?LET(N, choose(0, 6),
|
?LET(N, choose(0, 6),
|
||||||
?LETSHRINK(Values, fate_values(Size, N, Options),
|
?LETSHRINK(Values, fate_values(Size, N, Options),
|
||||||
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map, store_map])),
|
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map, store_map])),
|
||||||
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
return(gmb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
fate_store_map() ->
|
fate_store_map() ->
|
||||||
%% only #{} is allowed as cache in serialization
|
%% only #{} is allowed as cache in serialization
|
||||||
?LET(X, oneof([int(), largeint()]),
|
?LET(X, oneof([int(), largeint()]),
|
||||||
return(aeb_fate_data:make_store_map(abs(X)))).
|
return(gmb_fate_data:make_store_map(abs(X)))).
|
||||||
|
|
||||||
fate_bad_map() ->
|
fate_bad_map() ->
|
||||||
?LET(N, choose(0, 6),
|
?LET(N, choose(0, 6),
|
||||||
?LET(Values, vector(N, ?SIZED(Size, resize(Size div 8, fate_data()))),
|
?LET(Values, vector(N, ?SIZED(Size, resize(Size div 8, fate_data()))),
|
||||||
?LET(Keys, vector(N, ?SIZED(Size, resize(Size div 4, fate_data()))),
|
?LET(Keys, vector(N, ?SIZED(Size, resize(Size div 4, fate_data()))),
|
||||||
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
return(gmb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
non_quote_string() ->
|
non_quote_string() ->
|
||||||
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
@ -5,7 +5,7 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
-module(aefate_type_eqc).
|
-module(gmfate_type_eqc).
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
|
||||||
@ -18,11 +18,11 @@ prop_roundtrip() ->
|
|||||||
?FORALL(FateType, fate_type(),
|
?FORALL(FateType, fate_type(),
|
||||||
collect(kind(FateType),
|
collect(kind(FateType),
|
||||||
begin
|
begin
|
||||||
Serialized = aeb_fate_encoding:serialize_type(FateType),
|
Serialized = gmb_fate_encoding:serialize_type(FateType),
|
||||||
BinSerialized = list_to_binary(Serialized),
|
BinSerialized = list_to_binary(Serialized),
|
||||||
?WHENFAIL(eqc:format("Serialized ~p to ~p (~p)~n", [FateType, Serialized, BinSerialized]),
|
?WHENFAIL(eqc:format("Serialized ~p to ~p (~p)~n", [FateType, Serialized, BinSerialized]),
|
||||||
begin
|
begin
|
||||||
{Type, <<>>} = aeb_fate_encoding:deserialize_type(BinSerialized),
|
{Type, <<>>} = gmb_fate_encoding:deserialize_type(BinSerialized),
|
||||||
equals(Type, FateType)
|
equals(Type, FateType)
|
||||||
end)
|
end)
|
||||||
end)).
|
end)).
|
22
rebar.config
22
rebar.config
@ -5,14 +5,14 @@
|
|||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
{deps, [ {eblake2, "1.0.0"}
|
{deps, [ {eblake2, "1.0.0"}
|
||||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
, {gmserialization, {git, "https://git.qpq.swiss/QPQ-AG/gmserialization.git",
|
||||||
{ref, "47aaa8f"}}}
|
{ref, "9d2ecc00d32ea295309563e54a81636ecb597e96"}}}
|
||||||
, {getopt, "1.0.1"}
|
, {getopt, "1.0.1"}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{escript_incl_apps, [aebytecode, eblake2, aeserialization, getopt]}.
|
{escript_incl_apps, [gmbytecode, eblake2, gmserialization, getopt]}.
|
||||||
{escript_main_app, aebytecode}.
|
{escript_main_app, gmbytecode}.
|
||||||
{escript_name, aefateasm}.
|
{escript_name, gmfateasm}.
|
||||||
{escript_emu_args, "%%!"}.
|
{escript_emu_args, "%%!"}.
|
||||||
|
|
||||||
{pre_hooks,
|
{pre_hooks,
|
||||||
@ -29,8 +29,8 @@
|
|||||||
]}.
|
]}.
|
||||||
|
|
||||||
|
|
||||||
{relx, [{release, {aebytecode, "2.0.1"},
|
{relx, [{release, {gmbytecode, "3.4.1"},
|
||||||
[aebytecode, eblake2, getopt]},
|
[gmbytecode, eblake2, getopt]},
|
||||||
|
|
||||||
{dev_mode, true},
|
{dev_mode, true},
|
||||||
{include_erts, false},
|
{include_erts, false},
|
||||||
@ -39,17 +39,17 @@
|
|||||||
|
|
||||||
{profiles, [{binary, [
|
{profiles, [{binary, [
|
||||||
{deps, [ {eblake2, "1.0.0"}
|
{deps, [ {eblake2, "1.0.0"}
|
||||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
, {gmserialization, {git, "https://git.qpq.swiss/QPQ-AG/gmserialization.git",
|
||||||
{ref, "47aaa8f"}}}
|
{ref, "9d2ecc00d32ea295309563e54a81636ecb597e96"}}}
|
||||||
, {getopt, "1.0.1"}
|
, {getopt, "1.0.1"}
|
||||||
]},
|
]},
|
||||||
|
|
||||||
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
|
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
|
||||||
escriptize,
|
escriptize,
|
||||||
"cp \"$REBAR_BUILD_DIR/bin/aefateasm\" ./aefateasm"},
|
"cp \"$REBAR_BUILD_DIR/bin/gmfateasm\" ./gmfateasm"},
|
||||||
{"win32",
|
{"win32",
|
||||||
escriptize,
|
escriptize,
|
||||||
"robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ aefateasm* "
|
"robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ gmfateasm* "
|
||||||
"/njs /njh /nfl /ndl & exit /b 0"} % silence things
|
"/njs /njh /nfl /ndl & exit /b 0"} % silence things
|
||||||
]}
|
]}
|
||||||
]},
|
]},
|
||||||
|
21
rebar.lock
21
rebar.lock
@ -1,20 +1,23 @@
|
|||||||
{"1.1.0",
|
{"1.2.0",
|
||||||
[{<<"aeserialization">>,
|
[{<<"gmserialization">>,
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
|
||||||
{ref,"47aaa8f5434b365c50a35bfd1490340b19241991"}},
|
{ref,"9d2ecc00d32ea295309563e54a81636ecb597e96"}},
|
||||||
0},
|
0},
|
||||||
{<<"base58">>,
|
{<<"base58">>,
|
||||||
{git,"https://github.com/aeternity/erl-base58.git",
|
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
|
||||||
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
|
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
|
||||||
1},
|
1},
|
||||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||||
{<<"enacl">>,
|
{<<"enacl">>,
|
||||||
{git,"https://github.com/aeternity/enacl.git",
|
{git,"https://git.qpq.swiss/QPQ-AG/enacl.git",
|
||||||
{ref,"26180f42c0b3a450905d2efd8bc7fd5fd9cece75"}},
|
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
|
||||||
1},
|
1},
|
||||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
|
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
|
||||||
[
|
[
|
||||||
{pkg_hash,[
|
{pkg_hash,[
|
||||||
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
|
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
|
||||||
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]}
|
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
|
||||||
|
{pkg_hash_ext,[
|
||||||
|
{<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>},
|
||||||
|
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
|
||||||
].
|
].
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Encode and decode data and function calls according to
|
%%% Encode and decode data and function calls according to
|
||||||
%%% Sophia-AEVM-ABI
|
%%% Sophia-AEVM-ABI
|
||||||
%%% @end
|
%%% @end
|
||||||
|
%%% Updated : 22 Jan 2025
|
||||||
%%% Created : 25 Jan 2018
|
%%% Created : 25 Jan 2018
|
||||||
%%%
|
%%%
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeb_aevm_abi).
|
-module(gmb_aevm_abi).
|
||||||
|
-vsn("3.4.1").
|
||||||
-define(HASH_SIZE, 32).
|
-define(HASH_SIZE, 32).
|
||||||
|
|
||||||
-export([ create_calldata/4
|
-export([ create_calldata/4
|
||||||
@ -25,7 +28,7 @@
|
|||||||
|
|
||||||
-type hash() :: <<_:256>>. %% 256 = ?HASH_SIZE * 8.
|
-type hash() :: <<_:256>>. %% 256 = ?HASH_SIZE * 8.
|
||||||
-type function_name() :: binary(). %% String
|
-type function_name() :: binary(). %% String
|
||||||
-type typerep() :: aeb_aevm_data:type().
|
-type typerep() :: gmb_aevm_data:type().
|
||||||
-type function_type_info() :: { FunctionHash :: hash()
|
-type function_type_info() :: { FunctionHash :: hash()
|
||||||
, FunctionName :: function_name()
|
, FunctionName :: function_name()
|
||||||
, Payable :: boolean()
|
, Payable :: boolean()
|
||||||
@ -50,7 +53,7 @@ create_calldata(FunName, Args, ArgTypes0, RetType) ->
|
|||||||
ArgTypes = {tuple, ArgTypes0},
|
ArgTypes = {tuple, ArgTypes0},
|
||||||
<<TypeHashInt:?HASH_SIZE/unit:8>> =
|
<<TypeHashInt:?HASH_SIZE/unit:8>> =
|
||||||
function_type_hash(list_to_binary(FunName), ArgTypes, RetType),
|
function_type_hash(list_to_binary(FunName), ArgTypes, RetType),
|
||||||
Data = aeb_heap:to_binary({TypeHashInt, list_to_tuple(Args)}),
|
Data = gmb_heap:to_binary({TypeHashInt, list_to_tuple(Args)}),
|
||||||
{ok, Data}.
|
{ok, Data}.
|
||||||
|
|
||||||
-spec check_calldata(binary(), type_info(), boolean()) ->
|
-spec check_calldata(binary(), type_info(), boolean()) ->
|
||||||
@ -73,7 +76,7 @@ check_calldata(Hash, CallData, TypeInfo, true) ->
|
|||||||
check_calldata(Hash, CallData, TypeInfo, false) ->
|
check_calldata(Hash, CallData, TypeInfo, false) ->
|
||||||
case typereps_from_type_hash(Hash, TypeInfo) of
|
case typereps_from_type_hash(Hash, TypeInfo) of
|
||||||
{ok, ArgType, OutType} ->
|
{ok, ArgType, OutType} ->
|
||||||
try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of
|
try gmb_heap:from_binary({tuple, [word, ArgType]}, CallData) of
|
||||||
{ok, _Something} ->
|
{ok, _Something} ->
|
||||||
{ok, {tuple, [word, ArgType]}, OutType};
|
{ok, {tuple, [word, ArgType]}, OutType};
|
||||||
{error, _} ->
|
{error, _} ->
|
||||||
@ -90,7 +93,7 @@ check_calldata(Hash, CallData, TypeInfo, false) ->
|
|||||||
-spec get_function_hash_from_calldata(CallData::binary()) ->
|
-spec get_function_hash_from_calldata(CallData::binary()) ->
|
||||||
{ok, binary()} | {error, term()}.
|
{ok, binary()} | {error, term()}.
|
||||||
get_function_hash_from_calldata(CallData) ->
|
get_function_hash_from_calldata(CallData) ->
|
||||||
case aeb_heap:from_binary({tuple, [word]}, CallData) of
|
case gmb_heap:from_binary({tuple, [word]}, CallData) of
|
||||||
{ok, {HashInt}} -> {ok, <<HashInt:?HASH_SIZE/unit:8>>};
|
{ok, {HashInt}} -> {ok, <<HashInt:?HASH_SIZE/unit:8>>};
|
||||||
{error, _} = Error -> Error
|
{error, _} = Error -> Error
|
||||||
end.
|
end.
|
||||||
@ -105,15 +108,15 @@ function_type_info(Name, Payable, ArgTypes, OutType) ->
|
|||||||
{ function_type_hash(Name, ArgType, OutType)
|
{ function_type_hash(Name, ArgType, OutType)
|
||||||
, Name
|
, Name
|
||||||
, Payable
|
, Payable
|
||||||
, aeb_heap:to_binary(ArgType)
|
, gmb_heap:to_binary(ArgType)
|
||||||
, aeb_heap:to_binary(OutType)
|
, gmb_heap:to_binary(OutType)
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-spec function_type_hash(function_name(), typerep(), typerep()) -> hash().
|
-spec function_type_hash(function_name(), typerep(), typerep()) -> hash().
|
||||||
function_type_hash(Name, ArgType, OutType) when is_binary(Name) ->
|
function_type_hash(Name, ArgType, OutType) when is_binary(Name) ->
|
||||||
Bin = iolist_to_binary([ Name
|
Bin = iolist_to_binary([ Name
|
||||||
, aeb_heap:to_binary(ArgType)
|
, gmb_heap:to_binary(ArgType)
|
||||||
, aeb_heap:to_binary(OutType)
|
, gmb_heap:to_binary(OutType)
|
||||||
]),
|
]),
|
||||||
%% Calculate a 256 bit digest BLAKE2b hash value of a binary
|
%% Calculate a 256 bit digest BLAKE2b hash value of a binary
|
||||||
{ok, Hash} = eblake2:blake2b(?HASH_SIZE, Bin),
|
{ok, Hash} = eblake2:blake2b(?HASH_SIZE, Bin),
|
||||||
@ -132,7 +135,7 @@ arg_typerep_from_function(Function, TypeInfo) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
arg_typerep_from_type_binary(ArgTBin) ->
|
arg_typerep_from_type_binary(ArgTBin) ->
|
||||||
case aeb_heap:from_binary(typerep, ArgTBin) of
|
case gmb_heap:from_binary(typerep, ArgTBin) of
|
||||||
{ok, ArgT} -> {ok, ArgT};
|
{ok, ArgT} -> {ok, ArgT};
|
||||||
{error,_} -> {error, bad_type_data}
|
{error,_} -> {error, bad_type_data}
|
||||||
end.
|
end.
|
||||||
@ -150,7 +153,7 @@ typereps_from_type_hash(TypeHash, TypeInfo) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
typereps_from_type_binaries(ArgTBin, OutTBin) ->
|
typereps_from_type_binaries(ArgTBin, OutTBin) ->
|
||||||
case {aeb_heap:from_binary(typerep, ArgTBin), aeb_heap:from_binary(typerep, OutTBin)} of
|
case {gmb_heap:from_binary(typerep, ArgTBin), gmb_heap:from_binary(typerep, OutTBin)} of
|
||||||
{{ok, ArgT}, {ok, OutT}} -> {ok, ArgT, OutT};
|
{{ok, ArgT}, {ok, OutT}} -> {ok, ArgT, OutT};
|
||||||
{_, _} -> {error, bad_type_data}
|
{_, _} -> {error, bad_type_data}
|
||||||
end.
|
end.
|
@ -1,4 +1,5 @@
|
|||||||
-module(aeb_aevm_data).
|
-module(gmb_aevm_data).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export_type([data/0,
|
-export_type([data/0,
|
||||||
type/0,
|
type/0,
|
@ -1,4 +1,5 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||||
%%% @doc Assembler for aevm machine code.
|
%%% @doc Assembler for aevm machine code.
|
||||||
%%%
|
%%%
|
||||||
@ -25,17 +26,19 @@
|
|||||||
%%% 4. labels as descibed above.
|
%%% 4. labels as descibed above.
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
|
%%% Updated : 22 Jan 2025
|
||||||
%%% Created : 21 Dec 2017
|
%%% Created : 21 Dec 2017
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_asm).
|
-module(gmb_asm).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ file/2
|
-export([ file/2
|
||||||
, pp/1
|
, pp/1
|
||||||
, to_hexstring/1
|
, to_hexstring/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
pp(Asm) ->
|
pp(Asm) ->
|
||||||
@ -47,10 +50,10 @@ format(Asm) -> format(Asm, 0).
|
|||||||
format([{comment, Comment} | Rest], Address) ->
|
format([{comment, Comment} | Rest], Address) ->
|
||||||
";; " ++ Comment ++ "\n" ++ format(Rest, Address);
|
";; " ++ Comment ++ "\n" ++ format(Rest, Address);
|
||||||
format([Mnemonic | Rest], Address) ->
|
format([Mnemonic | Rest], Address) ->
|
||||||
Op = aeb_opcodes:m_to_op(Mnemonic),
|
Op = gmb_opcodes:m_to_op(Mnemonic),
|
||||||
case (Op >= ?PUSH1) andalso (Op =< ?PUSH32) of
|
case (Op >= ?PUSH1) andalso (Op =< ?PUSH32) of
|
||||||
true ->
|
true ->
|
||||||
Arity = aeb_opcodes:op_size(Op) - 1,
|
Arity = gmb_opcodes:op_size(Op) - 1,
|
||||||
{Args, Code} = get_args(Arity, Rest),
|
{Args, Code} = get_args(Arity, Rest),
|
||||||
" " ++ atom_to_list(Mnemonic)
|
" " ++ atom_to_list(Mnemonic)
|
||||||
++ " " ++ Args ++ "\n"
|
++ " " ++ Args ++ "\n"
|
||||||
@ -72,7 +75,7 @@ get_args(N, [Arg|Code]) ->
|
|||||||
|
|
||||||
file(Filename, Options) ->
|
file(Filename, Options) ->
|
||||||
{ok, File} = file:read_file(Filename),
|
{ok, File} = file:read_file(Filename),
|
||||||
{ok, Tokens, _} = aeb_asm_scan:scan(binary_to_list(File)),
|
{ok, Tokens, _} = gmb_asm_scan:scan(binary_to_list(File)),
|
||||||
|
|
||||||
case proplists:lookup(pp_tokens, Options) of
|
case proplists:lookup(pp_tokens, Options) of
|
||||||
{pp_tokens, true} ->
|
{pp_tokens, true} ->
|
||||||
@ -100,8 +103,8 @@ to_hexstring(ByteList) ->
|
|||||||
|
|
||||||
|
|
||||||
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
|
||||||
OpCode = aeb_opcodes:m_to_op(Op),
|
OpCode = gmb_opcodes:m_to_op(Op),
|
||||||
OpSize = aeb_opcodes:op_size(OpCode),
|
OpSize = gmb_opcodes:op_size(OpCode),
|
||||||
to_bytecode(Rest, Address + OpSize, Env, [OpCode|Code], Opts);
|
to_bytecode(Rest, Address + OpSize, Env, [OpCode|Code], Opts);
|
||||||
to_bytecode([{int,_line, Int}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{int,_line, Int}|Rest], Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env, [Int|Code], Opts);
|
to_bytecode(Rest, Address, Env, [Int|Code], Opts);
|
||||||
@ -138,7 +141,7 @@ resolve_refs([Op | Rest], Env, Code) ->
|
|||||||
resolve_refs([],_Env, Code) -> Code.
|
resolve_refs([],_Env, Code) -> Code.
|
||||||
|
|
||||||
expand_args([OP, Arg | Rest]) when OP >= ?PUSH1 andalso OP =< ?PUSH32 ->
|
expand_args([OP, Arg | Rest]) when OP >= ?PUSH1 andalso OP =< ?PUSH32 ->
|
||||||
BitSize = (aeb_opcodes:op_size(OP) - 1) * 8,
|
BitSize = (gmb_opcodes:op_size(OP) - 1) * 8,
|
||||||
Bin = << << X:BitSize>> || X <- [Arg] >>,
|
Bin = << << X:BitSize>> || X <- [Arg] >>,
|
||||||
ArgByteList = binary_to_list(Bin),
|
ArgByteList = binary_to_list(Bin),
|
||||||
[OP | ArgByteList] ++ expand_args(Rest);
|
[OP | ArgByteList] ++ expand_args(Rest);
|
@ -1,5 +1,6 @@
|
|||||||
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||||
%%% @doc Assembler lexer.
|
%%% @doc Assembler lexer.
|
||||||
%%%
|
%%%
|
||||||
@ -195,7 +196,7 @@ Erlang code.
|
|||||||
|
|
||||||
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
|
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
|
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
|
@ -1,19 +1,22 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Prettyprint aevm machine code
|
%%% Prettyprint aevm machine code
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 2 Oct 2017
|
%%% Updated : 22 Jan 2025
|
||||||
|
%%% Created : 02 Oct 2017
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_disassemble).
|
-module(gmb_disassemble).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ pp/1,
|
-export([ pp/1,
|
||||||
format/2,
|
format/2,
|
||||||
format_address/1
|
format_address/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
pp(Binary) ->
|
pp(Binary) ->
|
||||||
@ -26,37 +29,37 @@ format(Binary, ErrFormatFun) ->
|
|||||||
pp(Address, [Op|Ops], Assembly, ErrFormatFun) ->
|
pp(Address, [Op|Ops], Assembly, ErrFormatFun) ->
|
||||||
case Op of
|
case Op of
|
||||||
X when (X >= ?STOP) andalso (X =< ?SIGNEXTEND) ->
|
X when (X >= ?STOP) andalso (X =< ?SIGNEXTEND) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?LT) andalso (X =< ?BYTE) ->
|
X when (X >= ?LT) andalso (X =< ?BYTE) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?SHA3) andalso (X =< ?SHA3) ->
|
X when (X >= ?SHA3) andalso (X =< ?SHA3) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?ADDRESS) andalso (X =< ?EXTCODECOPY) ->
|
X when (X >= ?ADDRESS) andalso (X =< ?EXTCODECOPY) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?BLOCKHASH) andalso (X =< ?GASLIMIT) ->
|
X when (X >= ?BLOCKHASH) andalso (X =< ?GASLIMIT) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?POP) andalso (X =< ?JUMPDEST) ->
|
X when (X >= ?POP) andalso (X =< ?JUMPDEST) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?PUSH1) andalso (X =< ?PUSH32) ->
|
X when (X >= ?PUSH1) andalso (X =< ?PUSH32) ->
|
||||||
Bytes = X-?PUSH1+1,
|
Bytes = X-?PUSH1+1,
|
||||||
{ArgList, NextOps} = lists:split(Bytes, Ops),
|
{ArgList, NextOps} = lists:split(Bytes, Ops),
|
||||||
Arg = arglist_to_arg(ArgList),
|
Arg = arglist_to_arg(ArgList),
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), [{Arg,8*Bytes}]),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), [{Arg,8*Bytes}]),
|
||||||
next(Address+Bytes, NextOps, Instr, Assembly, ErrFormatFun);
|
next(Address+Bytes, NextOps, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?DUP1) andalso (X =< ?LOG4) ->
|
X when (X >= ?DUP1) andalso (X =< ?LOG4) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?CREATE) andalso (X =< ?DELEGATECALL) ->
|
X when (X >= ?CREATE) andalso (X =< ?DELEGATECALL) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
X when (X >= ?INVALID) andalso (X =< ?SUICIDE) ->
|
X when (X >= ?INVALID) andalso (X =< ?SUICIDE) ->
|
||||||
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
|
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
|
||||||
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
next(Address, Ops, Instr, Assembly, ErrFormatFun);
|
||||||
_ ->
|
_ ->
|
||||||
ErrFormatFun("unhandled op ~p at ~p",[Op, Address]),
|
ErrFormatFun("unhandled op ~p at ~p",[Op, Address]),
|
@ -1,13 +1,16 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Encode and decode data and function calls according to
|
%%% Encode and decode data and function calls according to
|
||||||
%%% Sophia-FATE-ABI
|
%%% Sophia-FATE-ABI
|
||||||
%%% @end
|
%%% @end
|
||||||
|
%%% Updated : 22 Jan 2025
|
||||||
%%% Created : 11 Jun 2019
|
%%% Created : 11 Jun 2019
|
||||||
%%%
|
%%%
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeb_fate_abi).
|
-module(gmb_fate_abi).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ create_calldata/2
|
-export([ create_calldata/2
|
||||||
, decode_calldata/2
|
, decode_calldata/2
|
||||||
@ -16,7 +19,7 @@
|
|||||||
, get_function_type_from_function_hash/2
|
, get_function_type_from_function_hash/2
|
||||||
, abi_version/0 ]).
|
, abi_version/0 ]).
|
||||||
|
|
||||||
-include("../include/aeb_fate_data.hrl").
|
-include("../include/gmb_fate_data.hrl").
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
@ -29,27 +32,27 @@ abi_version() ->
|
|||||||
|
|
||||||
-spec create_calldata(list(), [term()]) -> {ok, binary()}.
|
-spec create_calldata(list(), [term()]) -> {ok, binary()}.
|
||||||
create_calldata(FunName, Args) ->
|
create_calldata(FunName, Args) ->
|
||||||
FunctionId = aeb_fate_code:symbol_identifier(list_to_binary(FunName)),
|
FunctionId = gmb_fate_code:symbol_identifier(list_to_binary(FunName)),
|
||||||
{ok, aeb_fate_encoding:serialize(
|
{ok, gmb_fate_encoding:serialize(
|
||||||
aeb_fate_data:make_tuple({FunctionId,
|
gmb_fate_data:make_tuple({FunctionId,
|
||||||
aeb_fate_data:make_tuple(list_to_tuple(Args))}))}.
|
gmb_fate_data:make_tuple(list_to_tuple(Args))}))}.
|
||||||
|
|
||||||
-spec decode_calldata(list(), binary()) -> {ok, term()} | {error, term()}.
|
-spec decode_calldata(list(), binary()) -> {ok, term()} | {error, term()}.
|
||||||
decode_calldata(FunName, Calldata) ->
|
decode_calldata(FunName, Calldata) ->
|
||||||
FunctionId = aeb_fate_code:symbol_identifier(list_to_binary(FunName)),
|
FunctionId = gmb_fate_code:symbol_identifier(list_to_binary(FunName)),
|
||||||
try ?FATE_TUPLE_ELEMENTS(aeb_fate_encoding:deserialize(Calldata)) of
|
try ?FATE_TUPLE_ELEMENTS(gmb_fate_encoding:deserialize(Calldata)) of
|
||||||
[FunctionId, FateArgs] -> {ok, ?FATE_TUPLE_ELEMENTS(FateArgs)};
|
[FunctionId, FateArgs] -> {ok, ?FATE_TUPLE_ELEMENTS(FateArgs)};
|
||||||
_ -> {error, decode_error}
|
_ -> {error, decode_error}
|
||||||
catch _:_ ->
|
catch _:_ ->
|
||||||
{error, decode_error}
|
{error, decode_error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec get_function_name_from_function_hash(binary(), aeb_fate_code:fcode()) ->
|
-spec get_function_name_from_function_hash(binary(), gmb_fate_code:fcode()) ->
|
||||||
{ok, term()} | {error, term()}.
|
{ok, term()} | {error, term()}.
|
||||||
get_function_name_from_function_hash(<<SymbolHash:4/binary, _:28/binary>>, FateCode) ->
|
get_function_name_from_function_hash(<<SymbolHash:4/binary, _:28/binary>>, FateCode) ->
|
||||||
get_function_name_from_function_hash(SymbolHash, FateCode);
|
get_function_name_from_function_hash(SymbolHash, FateCode);
|
||||||
get_function_name_from_function_hash(SymbolHash = <<_:4/binary>>, FateCode) ->
|
get_function_name_from_function_hash(SymbolHash = <<_:4/binary>>, FateCode) ->
|
||||||
Symbols = aeb_fate_code:symbols(FateCode),
|
Symbols = gmb_fate_code:symbols(FateCode),
|
||||||
case maps:get(SymbolHash, Symbols, undefined) of
|
case maps:get(SymbolHash, Symbols, undefined) of
|
||||||
undefined -> {error, no_function_matching_function_hash};
|
undefined -> {error, no_function_matching_function_hash};
|
||||||
Function -> {ok, Function}
|
Function -> {ok, Function}
|
||||||
@ -58,19 +61,19 @@ get_function_name_from_function_hash(SymbolHash = <<_:4/binary>>, FateCode) ->
|
|||||||
-spec get_function_hash_from_calldata(binary()) ->
|
-spec get_function_hash_from_calldata(binary()) ->
|
||||||
{ok, binary()} | {error, term()}.
|
{ok, binary()} | {error, term()}.
|
||||||
get_function_hash_from_calldata(CallData) ->
|
get_function_hash_from_calldata(CallData) ->
|
||||||
try ?FATE_TUPLE_ELEMENTS(aeb_fate_encoding:deserialize(CallData)) of
|
try ?FATE_TUPLE_ELEMENTS(gmb_fate_encoding:deserialize(CallData)) of
|
||||||
[FunHash, _Args] -> {ok, FunHash};
|
[FunHash, _Args] -> {ok, FunHash};
|
||||||
_ -> {error, bad_calldata}
|
_ -> {error, bad_calldata}
|
||||||
catch _:_ ->
|
catch _:_ ->
|
||||||
{error, bad_calldata}
|
{error, bad_calldata}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec get_function_type_from_function_hash(binary(), aeb_fate_code:fcode()) ->
|
-spec get_function_type_from_function_hash(binary(), gmb_fate_code:fcode()) ->
|
||||||
{ok, term(), term()} | {error, term()}.
|
{ok, term(), term()} | {error, term()}.
|
||||||
get_function_type_from_function_hash(<<SymbolHash:4/binary, _:28/binary>>, FateCode) ->
|
get_function_type_from_function_hash(<<SymbolHash:4/binary, _:28/binary>>, FateCode) ->
|
||||||
get_function_type_from_function_hash(SymbolHash, FateCode);
|
get_function_type_from_function_hash(SymbolHash, FateCode);
|
||||||
get_function_type_from_function_hash(SymbolHash, FateCode) ->
|
get_function_type_from_function_hash(SymbolHash, FateCode) ->
|
||||||
Functions = aeb_fate_code:functions(FateCode),
|
Functions = gmb_fate_code:functions(FateCode),
|
||||||
case maps:get(SymbolHash, Functions, undefined) of
|
case maps:get(SymbolHash, Functions, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, no_function_matching_function_hash};
|
{error, no_function_matching_function_hash};
|
@ -1,4 +1,5 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
%%% @doc Assembler for Fate machine code.
|
%%% @doc Assembler for Fate machine code.
|
||||||
%%% @end
|
%%% @end
|
||||||
@ -80,10 +81,12 @@
|
|||||||
%%% Size: Digits
|
%%% Size: Digits
|
||||||
%%% Tag: Digits
|
%%% Tag: Digits
|
||||||
%%%
|
%%%
|
||||||
|
%%% Updated : 22 Jan 2025
|
||||||
%%% Created : 21 Dec 2017
|
%%% Created : 21 Dec 2017
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_fate_asm).
|
-module(gmb_fate_asm).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ assemble_file/3
|
-export([ assemble_file/3
|
||||||
, asm_to_bytecode/2
|
, asm_to_bytecode/2
|
||||||
@ -94,8 +97,8 @@
|
|||||||
, to_asm/1
|
, to_asm/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
|
-include_lib("gmbytecode/include/gmb_fate_opcodes.hrl").
|
||||||
-include_lib("aebytecode/include/aeb_fate_data.hrl").
|
-include_lib("gmbytecode/include/gmb_fate_data.hrl").
|
||||||
-define(HASH_BYTES, 32).
|
-define(HASH_BYTES, 32).
|
||||||
|
|
||||||
assemble_file(InFile, OutFile, Options) ->
|
assemble_file(InFile, OutFile, Options) ->
|
||||||
@ -104,12 +107,12 @@ assemble_file(InFile, OutFile, Options) ->
|
|||||||
ok = file:write_file(OutFile, BC).
|
ok = file:write_file(OutFile, BC).
|
||||||
|
|
||||||
function_call(String) ->
|
function_call(String) ->
|
||||||
{ok, Tokens, _} = aeb_fate_asm_scan:scan(String),
|
{ok, Tokens, _} = gmb_fate_asm_scan:scan(String),
|
||||||
parse_function_call(Tokens).
|
parse_function_call(Tokens).
|
||||||
|
|
||||||
parse_function_call([{id,_,Name}, {'(',_}| Rest]) ->
|
parse_function_call([{id,_,Name}, {'(',_}| Rest]) ->
|
||||||
{Args, []} = to_args(Rest),
|
{Args, []} = to_args(Rest),
|
||||||
aeb_fate_encoding:serialize(
|
gmb_fate_encoding:serialize(
|
||||||
{tuple, {mk_hash(Name), {tuple, list_to_tuple(Args)}}}).
|
{tuple, {mk_hash(Name), {tuple, list_to_tuple(Args)}}}).
|
||||||
|
|
||||||
|
|
||||||
@ -129,9 +132,9 @@ pp(FateCode) ->
|
|||||||
|
|
||||||
|
|
||||||
to_asm(FateCode) ->
|
to_asm(FateCode) ->
|
||||||
Functions = aeb_fate_code:functions(FateCode),
|
Functions = gmb_fate_code:functions(FateCode),
|
||||||
Symbols = aeb_fate_code:symbols(FateCode),
|
Symbols = gmb_fate_code:symbols(FateCode),
|
||||||
Annotations = aeb_fate_code:annotations(FateCode),
|
Annotations = gmb_fate_code:annotations(FateCode),
|
||||||
insert_comments(get_comments(Annotations), 1,
|
insert_comments(get_comments(Annotations), 1,
|
||||||
lists:flatten(
|
lists:flatten(
|
||||||
io_lib:format("~s",
|
io_lib:format("~s",
|
||||||
@ -191,7 +194,7 @@ format_code([], _) ->
|
|||||||
"";
|
"";
|
||||||
format_code([Op|Rest], Symbols) ->
|
format_code([Op|Rest], Symbols) ->
|
||||||
[" ",
|
[" ",
|
||||||
aeb_fate_pp:format_op(Op, Symbols),
|
gmb_fate_pp:format_op(Op, Symbols),
|
||||||
"\n",
|
"\n",
|
||||||
format_code(Rest, Symbols)].
|
format_code(Rest, Symbols)].
|
||||||
|
|
||||||
@ -201,7 +204,7 @@ read_file(Filename) ->
|
|||||||
binary_to_list(File).
|
binary_to_list(File).
|
||||||
|
|
||||||
asm_to_bytecode(AssemblerCode, Options) ->
|
asm_to_bytecode(AssemblerCode, Options) ->
|
||||||
{ok, Tokens, _} = aeb_fate_asm_scan:scan(AssemblerCode),
|
{ok, Tokens, _} = gmb_fate_asm_scan:scan(AssemblerCode),
|
||||||
|
|
||||||
case proplists:lookup(pp_tokens, Options) of
|
case proplists:lookup(pp_tokens, Options) of
|
||||||
{pp_tokens, true} ->
|
{pp_tokens, true} ->
|
||||||
@ -209,7 +212,7 @@ asm_to_bytecode(AssemblerCode, Options) ->
|
|||||||
none ->
|
none ->
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
Env = #{ fate_code => aeb_fate_code:new()
|
Env = #{ fate_code => gmb_fate_code:new()
|
||||||
, functions => #{}
|
, functions => #{}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -218,11 +221,11 @@ asm_to_bytecode(AssemblerCode, Options) ->
|
|||||||
FunctionsMap = maps:get(functions, Env1),
|
FunctionsMap = maps:get(functions, Env1),
|
||||||
Functions = [X || {_, X} <- lists:sort(maps:to_list(FunctionsMap))],
|
Functions = [X || {_, X} <- lists:sort(maps:to_list(FunctionsMap))],
|
||||||
FunctionsBin = iolist_to_binary(Functions),
|
FunctionsBin = iolist_to_binary(Functions),
|
||||||
ByteCode = aeb_fate_code:serialize(FateCode, FunctionsBin, Options),
|
ByteCode = gmb_fate_code:serialize(FateCode, FunctionsBin, Options),
|
||||||
{Env, ByteCode}.
|
{Env, ByteCode}.
|
||||||
|
|
||||||
strip(ByteCode) ->
|
strip(ByteCode) ->
|
||||||
{Code, _Rest} = aeser_rlp:decode_one(ByteCode),
|
{Code, _Rest} = gmser_rlp:decode_one(ByteCode),
|
||||||
Code.
|
Code.
|
||||||
|
|
||||||
%% -------------------------------------------------------------------
|
%% -------------------------------------------------------------------
|
||||||
@ -235,7 +238,7 @@ to_bytecode([{function,_line, 'FUNCTION'}|Rest], Address, Env, Code, Opts) ->
|
|||||||
{Fun, Rest2} = to_fun_def(Rest),
|
{Fun, Rest2} = to_fun_def(Rest),
|
||||||
to_bytecode(Rest2, Fun, Env2, [], Opts);
|
to_bytecode(Rest2, Fun, Env2, [], Opts);
|
||||||
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
|
||||||
OpCode = aeb_fate_opcodes:m_to_op(Op),
|
OpCode = gmb_fate_opcodes:m_to_op(Op),
|
||||||
to_bytecode(Rest, Address, Env, [OpCode|Code], Opts);
|
to_bytecode(Rest, Address, Env, [OpCode|Code], Opts);
|
||||||
to_bytecode([{arg,_line, N}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{arg,_line, N}|Rest], Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env, [{arg, N}|Code], Opts);
|
to_bytecode(Rest, Address, Env, [{arg, N}|Code], Opts);
|
||||||
@ -249,41 +252,41 @@ to_bytecode([{boolean,_line, Bool}|Rest], Address, Env, Code, Opts) ->
|
|||||||
to_bytecode(Rest, Address, Env, [{immediate, Bool}|Code], Opts);
|
to_bytecode(Rest, Address, Env, [{immediate, Bool}|Code], Opts);
|
||||||
to_bytecode([{string,_line, String}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{string,_line, String}|Rest], Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_string(String)}|Code],
|
[{immediate, gmb_fate_data:make_string(String)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{object,_line, {address, Value}}|Rest],
|
to_bytecode([{object,_line, {address, Value}}|Rest],
|
||||||
Address, Env, Code, Opts) ->
|
Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_address(Value)}|Code],
|
[{immediate, gmb_fate_data:make_address(Value)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{object,_line, {contract, Value}}|Rest],
|
to_bytecode([{object,_line, {contract, Value}}|Rest],
|
||||||
Address, Env, Code, Opts) ->
|
Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_contract(Value)}|Code],
|
[{immediate, gmb_fate_data:make_contract(Value)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{object,_line, {oracle, Value}}|Rest],
|
to_bytecode([{object,_line, {oracle, Value}}|Rest],
|
||||||
Address, Env, Code, Opts) ->
|
Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_oracle(Value)}|Code],
|
[{immediate, gmb_fate_data:make_oracle(Value)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{object,_line, {oracle_query, Value}}|Rest],
|
to_bytecode([{object,_line, {oracle_query, Value}}|Rest],
|
||||||
Address, Env, Code, Opts) ->
|
Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_oracle_query(Value)}|Code],
|
[{immediate, gmb_fate_data:make_oracle_query(Value)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{object,_line, {channel, Value}}|Rest],
|
to_bytecode([{object,_line, {channel, Value}}|Rest],
|
||||||
Address, Env, Code, Opts) ->
|
Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_contract(Value)}|Code],
|
[{immediate, gmb_fate_data:make_contract(Value)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{bytes,_line, Value}|Rest],
|
to_bytecode([{bytes,_line, Value}|Rest],
|
||||||
Address, Env, Code, Opts) ->
|
Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_bytes(Value)}|Code],
|
[{immediate, gmb_fate_data:make_bytes(Value)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{contract_bytearray,_line, FateCode}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{contract_bytearray,_line, FateCode}|Rest], Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_contract_bytearray(FateCode)}|Code],
|
[{immediate, gmb_fate_data:make_contract_bytearray(FateCode)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
|
||||||
{Env2, Id} = insert_symbol(list_to_binary(ID), Env),
|
{Env2, Id} = insert_symbol(list_to_binary(ID), Env),
|
||||||
@ -296,19 +299,19 @@ to_bytecode([{'[',_line}|Rest], Address, Env, Code, Opts) ->
|
|||||||
to_bytecode(Rest2, Address, Env, [{immediate, List}|Code], Opts);
|
to_bytecode(Rest2, Address, Env, [{immediate, List}|Code], Opts);
|
||||||
to_bytecode([{'(',_line}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{'(',_line}|Rest], Address, Env, Code, Opts) ->
|
||||||
{Elements, Rest2} = parse_tuple(Rest),
|
{Elements, Rest2} = parse_tuple(Rest),
|
||||||
Tuple = aeb_fate_data:make_tuple(list_to_tuple(Elements)),
|
Tuple = gmb_fate_data:make_tuple(list_to_tuple(Elements)),
|
||||||
to_bytecode(Rest2, Address, Env, [{immediate, Tuple}|Code], Opts);
|
to_bytecode(Rest2, Address, Env, [{immediate, Tuple}|Code], Opts);
|
||||||
to_bytecode([{start_variant,_line}|_] = Tokens, Address, Env, Code, Opts) ->
|
to_bytecode([{start_variant,_line}|_] = Tokens, Address, Env, Code, Opts) ->
|
||||||
{Arities, Tag, Values, Rest} = parse_variant(Tokens),
|
{Arities, Tag, Values, Rest} = parse_variant(Tokens),
|
||||||
Variant = aeb_fate_data:make_variant(Arities, Tag, Values),
|
Variant = gmb_fate_data:make_variant(Arities, Tag, Values),
|
||||||
to_bytecode(Rest, Address, Env, [{immediate, Variant}|Code], Opts);
|
to_bytecode(Rest, Address, Env, [{immediate, Variant}|Code], Opts);
|
||||||
to_bytecode([{typerep,_line}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{typerep,_line}|Rest], Address, Env, Code, Opts) ->
|
||||||
{Type, Rest1} = to_type(Rest),
|
{Type, Rest1} = to_type(Rest),
|
||||||
TypeRep = aeb_fate_data:make_typerep(Type),
|
TypeRep = gmb_fate_data:make_typerep(Type),
|
||||||
to_bytecode(Rest1, Address, Env, [{immediate, TypeRep}|Code], Opts);
|
to_bytecode(Rest1, Address, Env, [{immediate, TypeRep}|Code], Opts);
|
||||||
to_bytecode([{bits,_line, Bits}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{bits,_line, Bits}|Rest], Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env,
|
to_bytecode(Rest, Address, Env,
|
||||||
[{immediate, aeb_fate_data:make_bits(Bits)}|Code], Opts);
|
[{immediate, gmb_fate_data:make_bits(Bits)}|Code], Opts);
|
||||||
|
|
||||||
to_bytecode([{comment, Line, Comment}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{comment, Line, Comment}|Rest], Address, Env, Code, Opts) ->
|
||||||
Env2 = insert_annotation(comment, Line, Comment, Env),
|
Env2 = insert_annotation(comment, Line, Comment, Env),
|
||||||
@ -356,7 +359,7 @@ parse_tuple(Tokens) ->
|
|||||||
|
|
||||||
|
|
||||||
parse_variant([{start_variant,_line}
|
parse_variant([{start_variant,_line}
|
||||||
, {'[', _line}
|
, {'[', _}
|
||||||
| Rest]) ->
|
| Rest]) ->
|
||||||
{Arities, Rest2} = parse_list(Rest),
|
{Arities, Rest2} = parse_list(Rest),
|
||||||
%% Make sure Arities is a list of bytes.
|
%% Make sure Arities is a list of bytes.
|
||||||
@ -364,7 +367,7 @@ parse_variant([{start_variant,_line}
|
|||||||
is_integer(A), A < 256],
|
is_integer(A), A < 256],
|
||||||
|
|
||||||
[{'|',_}
|
[{'|',_}
|
||||||
, {int,_line, Tag}
|
, {int,_, Tag}
|
||||||
, {'|',_}
|
, {'|',_}
|
||||||
, {'(',_} | Rest3] = Rest2,
|
, {'(',_} | Rest3] = Rest2,
|
||||||
{Elements , [{end_variant, _} | Rest4]} = parse_tuple(Rest3),
|
{Elements , [{end_variant, _} | Rest4]} = parse_tuple(Rest3),
|
||||||
@ -383,29 +386,29 @@ parse_value([{'{',_line} | Rest]) -> parse_map(Rest);
|
|||||||
parse_value([{'[',_line} | Rest]) -> parse_list(Rest);
|
parse_value([{'[',_line} | Rest]) -> parse_list(Rest);
|
||||||
parse_value([{'(',_line} | Rest]) ->
|
parse_value([{'(',_line} | Rest]) ->
|
||||||
{T, Rest2} = parse_tuple(Rest),
|
{T, Rest2} = parse_tuple(Rest),
|
||||||
{aeb_fate_data:make_tuple(list_to_tuple(T)), Rest2};
|
{gmb_fate_data:make_tuple(list_to_tuple(T)), Rest2};
|
||||||
parse_value([{bits,_line, Bits} | Rest]) ->
|
parse_value([{bits,_line, Bits} | Rest]) ->
|
||||||
{aeb_fate_data:make_bits(Bits), Rest};
|
{gmb_fate_data:make_bits(Bits), Rest};
|
||||||
parse_value([{start_variant,_line}|_] = Tokens) ->
|
parse_value([{start_variant,_line}|_] = Tokens) ->
|
||||||
{Arities, Tag, Values, Rest} = parse_variant(Tokens),
|
{Arities, Tag, Values, Rest} = parse_variant(Tokens),
|
||||||
Variant = aeb_fate_data:make_variant(Arities, Tag, Values),
|
Variant = gmb_fate_data:make_variant(Arities, Tag, Values),
|
||||||
{Variant, Rest};
|
{Variant, Rest};
|
||||||
parse_value([{string,_line, String} | Rest]) ->
|
parse_value([{string,_line, String} | Rest]) ->
|
||||||
{aeb_fate_data:make_string(String), Rest};
|
{gmb_fate_data:make_string(String), Rest};
|
||||||
parse_value([{object,_line, {address, Address}} | Rest]) ->
|
parse_value([{object,_line, {address, Address}} | Rest]) ->
|
||||||
{aeb_fate_data:make_address(Address), Rest};
|
{gmb_fate_data:make_address(Address), Rest};
|
||||||
parse_value([{object,_line, {contract, Address}} | Rest]) ->
|
parse_value([{object,_line, {contract, Address}} | Rest]) ->
|
||||||
{aeb_fate_data:make_contract(Address), Rest};
|
{gmb_fate_data:make_contract(Address), Rest};
|
||||||
parse_value([{object,_line, {oracle, Address}} | Rest]) ->
|
parse_value([{object,_line, {oracle, Address}} | Rest]) ->
|
||||||
{aeb_fate_data:make_oracle(Address), Rest};
|
{gmb_fate_data:make_oracle(Address), Rest};
|
||||||
parse_value([{object,_line, {oracle_query, Address}} | Rest]) ->
|
parse_value([{object,_line, {oracle_query, Address}} | Rest]) ->
|
||||||
{aeb_fate_data:make_oracle_query(Address), Rest};
|
{gmb_fate_data:make_oracle_query(Address), Rest};
|
||||||
parse_value([{object,_line, {channel, Address}} | Rest]) ->
|
parse_value([{object,_line, {channel, Address}} | Rest]) ->
|
||||||
{aeb_fate_data:make_channel(Address), Rest};
|
{gmb_fate_data:make_channel(Address), Rest};
|
||||||
parse_value([{hash,_line, Hash} | Rest]) ->
|
parse_value([{hash,_line, Hash} | Rest]) ->
|
||||||
{aeb_fate_data:make_hash(Hash), Rest};
|
{gmb_fate_data:make_hash(Hash), Rest};
|
||||||
parse_value([{signature,_line, Hash} | Rest]) ->
|
parse_value([{signature,_line, Hash} | Rest]) ->
|
||||||
{aeb_fate_data:make_signature(Hash), Rest};
|
{gmb_fate_data:make_signature(Hash), Rest};
|
||||||
parse_value([{typerep,_line} | Rest]) ->
|
parse_value([{typerep,_line} | Rest]) ->
|
||||||
to_type(Rest).
|
to_type(Rest).
|
||||||
|
|
||||||
@ -485,20 +488,20 @@ insert_fun(none, [], Env) -> Env;
|
|||||||
insert_fun({NameString, ArgType, RetType}, Code, #{ fate_code := FateCode
|
insert_fun({NameString, ArgType, RetType}, Code, #{ fate_code := FateCode
|
||||||
, functions := Funs} = Env) ->
|
, functions := Funs} = Env) ->
|
||||||
Name = list_to_binary(NameString),
|
Name = list_to_binary(NameString),
|
||||||
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
{FateCode1, Id} = gmb_fate_code:insert_symbol(Name, FateCode),
|
||||||
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
|
BodyByteCode = gmb_fate_code:serialize_code(lists:reverse(Code)),
|
||||||
SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}),
|
SigByteCode = gmb_fate_code:serialize_signature({ArgType, RetType}),
|
||||||
FunByteCode = [?FUNCTION, Id, aeb_fate_encoding:serialize(0), SigByteCode, BodyByteCode],
|
FunByteCode = [?FUNCTION, Id, gmb_fate_encoding:serialize(0), SigByteCode, BodyByteCode],
|
||||||
Env#{ functions => Funs#{ Id => FunByteCode }
|
Env#{ functions => Funs#{ Id => FunByteCode }
|
||||||
, fate_code => FateCode1}.
|
, fate_code => FateCode1}.
|
||||||
|
|
||||||
insert_symbol(Name, #{ fate_code := FateCode } = Env) ->
|
insert_symbol(Name, #{ fate_code := FateCode } = Env) ->
|
||||||
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
{FateCode1, Id} = gmb_fate_code:insert_symbol(Name, FateCode),
|
||||||
{ Env#{ fate_code => FateCode1 }
|
{ Env#{ fate_code => FateCode1 }
|
||||||
, Id}.
|
, Id}.
|
||||||
|
|
||||||
insert_annotation(comment, Line, Comment, #{ fate_code := FateCode } = Env) ->
|
insert_annotation(comment, Line, Comment, #{ fate_code := FateCode } = Env) ->
|
||||||
FateCode1 = aeb_fate_code:insert_annotation(comment, Line, Comment, FateCode),
|
FateCode1 = gmb_fate_code:insert_annotation(comment, Line, Comment, FateCode),
|
||||||
Env#{ fate_code => FateCode1}.
|
Env#{ fate_code => FateCode1}.
|
||||||
|
|
||||||
mk_hash(Id) ->
|
mk_hash(Id) ->
|
@ -1,6 +1,7 @@
|
|||||||
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%%% @copyright (C) 2019, aeternity Anstalt
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Handling FATE code.
|
%%% Handling FATE code.
|
||||||
%%% @end
|
%%% @end
|
||||||
@ -100,7 +101,7 @@ Erlang code.
|
|||||||
|
|
||||||
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
|
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
|
-include_lib("gmbytecode/include/gmb_fate_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
|
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
|
||||||
@ -115,12 +116,12 @@ parse_hash("#" ++ Chars) ->
|
|||||||
base64:decode(Chars).
|
base64:decode(Chars).
|
||||||
|
|
||||||
parse_contract_bytearray("@" ++ Chars) ->
|
parse_contract_bytearray("@" ++ Chars) ->
|
||||||
case aeser_api_encoder:decode(unicode:characters_to_binary(Chars)) of
|
case gmser_api_encoder:decode(unicode:characters_to_binary(Chars)) of
|
||||||
{contract_bytearray, Bin} -> Bin
|
{contract_bytearray, Bin} -> Bin
|
||||||
end.
|
end.
|
||||||
|
|
||||||
parse_object([_|Chars]) ->
|
parse_object([_|Chars]) ->
|
||||||
case aeser_api_encoder:decode(unicode:characters_to_binary(Chars)) of
|
case gmser_api_encoder:decode(unicode:characters_to_binary(Chars)) of
|
||||||
{account_pubkey, Bin} -> {address, Bin};
|
{account_pubkey, Bin} -> {address, Bin};
|
||||||
{contract_pubkey, Bin} -> {contract, Bin};
|
{contract_pubkey, Bin} -> {contract, Bin};
|
||||||
{oracle_pubkey, Bin} -> {oracle, Bin};
|
{oracle_pubkey, Bin} -> {oracle, Bin};
|
@ -1,11 +1,13 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% ADT for fate byte code/fate code
|
%%% ADT for fate byte code/fate code
|
||||||
%%% @end
|
%%% @end
|
||||||
%%%
|
%%%
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeb_fate_code).
|
-module(gmb_fate_code).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ annotations/1
|
-export([ annotations/1
|
||||||
, deserialize/1
|
, deserialize/1
|
||||||
@ -24,14 +26,12 @@
|
|||||||
, symbols/1
|
, symbols/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("../include/aeb_fate_opcodes.hrl").
|
-include("../include/gmb_fate_opcodes.hrl").
|
||||||
-include("../include/aeb_fate_data.hrl").
|
-include("../include/gmb_fate_data.hrl").
|
||||||
|
|
||||||
-ifdef(EQC).
|
|
||||||
-export([ update_annotations/2
|
-export([ update_annotations/2
|
||||||
, update_functions/2
|
, update_functions/2
|
||||||
, update_symbols/2]).
|
, update_symbols/2]).
|
||||||
-endif.
|
|
||||||
|
|
||||||
-record(fcode, { functions = #{} :: map()
|
-record(fcode, { functions = #{} :: map()
|
||||||
, symbols = #{} :: map()
|
, symbols = #{} :: map()
|
||||||
@ -89,8 +89,8 @@ insert_symbol(Name, #fcode{ symbols = Syms } = F) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
insert_annotation(comment =_Type, Line, Comment, FCode) ->
|
insert_annotation(comment =_Type, Line, Comment, FCode) ->
|
||||||
Key = aeb_fate_data:make_tuple({aeb_fate_data:make_string("comment"), Line}),
|
Key = gmb_fate_data:make_tuple({gmb_fate_data:make_string("comment"), Line}),
|
||||||
Value = aeb_fate_data:make_string(Comment),
|
Value = gmb_fate_data:make_string(Comment),
|
||||||
update_annotations(FCode, #{ Key => Value }).
|
update_annotations(FCode, #{ Key => Value }).
|
||||||
|
|
||||||
strip_init_function(#fcode{ functions = Funs,
|
strip_init_function(#fcode{ functions = Funs,
|
||||||
@ -113,9 +113,9 @@ serialize(#fcode{} = F, Options) ->
|
|||||||
serialize(#fcode{} = F, Functions, Options) ->
|
serialize(#fcode{} = F, Functions, Options) ->
|
||||||
SymbolTable = serialize_symbol_table(F),
|
SymbolTable = serialize_symbol_table(F),
|
||||||
Annotatations = serialize_annotations(F),
|
Annotatations = serialize_annotations(F),
|
||||||
ByteCode = << (aeser_rlp:encode(Functions))/binary,
|
ByteCode = << (gmser_rlp:encode(Functions))/binary,
|
||||||
(aeser_rlp:encode(SymbolTable))/binary,
|
(gmser_rlp:encode(SymbolTable))/binary,
|
||||||
(aeser_rlp:encode(Annotatations))/binary
|
(gmser_rlp:encode(Annotatations))/binary
|
||||||
>>,
|
>>,
|
||||||
|
|
||||||
case proplists:lookup(pp_hex_string, Options) of
|
case proplists:lookup(pp_hex_string, Options) of
|
||||||
@ -141,20 +141,20 @@ serialize_functions(#fcode{ functions = Functions }) ->
|
|||||||
|
|
||||||
serialize_attributes(Attrs) ->
|
serialize_attributes(Attrs) ->
|
||||||
AttrVal = lists:sum([ attr_value(Attr) || Attr <- Attrs ]),
|
AttrVal = lists:sum([ attr_value(Attr) || Attr <- Attrs ]),
|
||||||
aeb_fate_encoding:serialize(?MAKE_FATE_INTEGER(AttrVal)).
|
gmb_fate_encoding:serialize(?MAKE_FATE_INTEGER(AttrVal)).
|
||||||
|
|
||||||
attr_value(private) -> 1;
|
attr_value(private) -> 1;
|
||||||
attr_value(payable) -> 2.
|
attr_value(payable) -> 2.
|
||||||
|
|
||||||
serialize_signature({Args, RetType}) ->
|
serialize_signature({Args, RetType}) ->
|
||||||
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
[gmb_fate_encoding:serialize_type({tuple, Args}) |
|
||||||
aeb_fate_encoding:serialize_type(RetType)].
|
gmb_fate_encoding:serialize_type(RetType)].
|
||||||
|
|
||||||
serialize_symbol_table(#fcode{ symbols = Symbols }) ->
|
serialize_symbol_table(#fcode{ symbols = Symbols }) ->
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
|
gmb_fate_encoding:serialize(gmb_fate_data:make_map(Symbols)).
|
||||||
|
|
||||||
serialize_annotations(#fcode{ annotations = Annotations }) ->
|
serialize_annotations(#fcode{ annotations = Annotations }) ->
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
|
gmb_fate_encoding:serialize(gmb_fate_data:make_map(Annotations)).
|
||||||
|
|
||||||
serialize_bbs(#{} = BBs) ->
|
serialize_bbs(#{} = BBs) ->
|
||||||
serialize_bbs(BBs, 0, []).
|
serialize_bbs(BBs, 0, []).
|
||||||
@ -176,7 +176,7 @@ serialize_op(Op) ->
|
|||||||
true -> tuple_to_list(Op);
|
true -> tuple_to_list(Op);
|
||||||
false -> [Op]
|
false -> [Op]
|
||||||
end,
|
end,
|
||||||
[aeb_fate_opcodes:m_to_op(Mnemonic) | serialize_code(Args)].
|
[gmb_fate_opcodes:m_to_op(Mnemonic) | serialize_code(Args)].
|
||||||
|
|
||||||
sanity_check(#fcode{ functions = Funs }) ->
|
sanity_check(#fcode{ functions = Funs }) ->
|
||||||
_ = [ case Def of
|
_ = [ case Def of
|
||||||
@ -215,12 +215,12 @@ sanity_check_op(IsLast, Op) ->
|
|||||||
true -> tuple_to_list(Op);
|
true -> tuple_to_list(Op);
|
||||||
false -> [Op]
|
false -> [Op]
|
||||||
end,
|
end,
|
||||||
safe_sanity_check(IsLast, aeb_fate_opcodes:m_to_op(Mnemonic), Args).
|
safe_sanity_check(IsLast, gmb_fate_opcodes:m_to_op(Mnemonic), Args).
|
||||||
|
|
||||||
safe_sanity_check(IsLast, Op, Args) ->
|
safe_sanity_check(IsLast, Op, Args) ->
|
||||||
case length(Args) == aeb_fate_opcodes:args(Op) of
|
case length(Args) == gmb_fate_opcodes:args(Op) of
|
||||||
true ->
|
true ->
|
||||||
case IsLast == aeb_fate_opcodes:end_bb(Op) of
|
case IsLast == gmb_fate_opcodes:end_bb(Op) of
|
||||||
true -> ok;
|
true -> ok;
|
||||||
false -> error({wrong_opcode_in_bb, Op})
|
false -> error({wrong_opcode_in_bb, Op})
|
||||||
end;
|
end;
|
||||||
@ -271,7 +271,7 @@ pad_args(List) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
serialize_data(_, Data) ->
|
serialize_data(_, Data) ->
|
||||||
aeb_fate_encoding:serialize(Data).
|
gmb_fate_encoding:serialize(Data).
|
||||||
|
|
||||||
%% 00 : stack/unused (depending on instruction)
|
%% 00 : stack/unused (depending on instruction)
|
||||||
%% 01 : argN
|
%% 01 : argN
|
||||||
@ -293,9 +293,9 @@ bits_to_modifier(2#00) -> stack.
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
deserialize(Bytes) ->
|
deserialize(Bytes) ->
|
||||||
{ByteCode, Rest1} = aeser_rlp:decode_one(Bytes),
|
{ByteCode, Rest1} = gmser_rlp:decode_one(Bytes),
|
||||||
{SymbolTable, Rest2} = aeser_rlp:decode_one(Rest1),
|
{SymbolTable, Rest2} = gmser_rlp:decode_one(Rest1),
|
||||||
{Annotations, <<>>} = aeser_rlp:decode_one(Rest2),
|
{Annotations, <<>>} = gmser_rlp:decode_one(Rest2),
|
||||||
|
|
||||||
Env = #{ function => none
|
Env = #{ function => none
|
||||||
, bb => 0
|
, bb => 0
|
||||||
@ -355,7 +355,7 @@ deserialize_functions(<<Op:8, Rest/binary>>,
|
|||||||
, current_bb_code := Code
|
, current_bb_code := Code
|
||||||
, code := Program} = Env) ->
|
, code := Program} = Env) ->
|
||||||
{Rest2, OpCode} = deserialize_op(Op, Rest, Code),
|
{Rest2, OpCode} = deserialize_op(Op, Rest, Code),
|
||||||
case aeb_fate_opcodes:end_bb(Op) of
|
case gmb_fate_opcodes:end_bb(Op) of
|
||||||
true ->
|
true ->
|
||||||
deserialize_functions(Rest2, Env#{ bb => BB+1
|
deserialize_functions(Rest2, Env#{ bb => BB+1
|
||||||
, current_bb_code => []
|
, current_bb_code => []
|
||||||
@ -380,8 +380,8 @@ deserialize_functions(<<>>, #{ function := {F, Attrs, Sig}
|
|||||||
Funs#{F => {Attrs, Sig, FunctionCode}}.
|
Funs#{F => {Attrs, Sig, FunctionCode}}.
|
||||||
|
|
||||||
deserialize_op(Op, Rest, Code) ->
|
deserialize_op(Op, Rest, Code) ->
|
||||||
OpName = aeb_fate_opcodes:mnemonic(Op),
|
OpName = gmb_fate_opcodes:mnemonic(Op),
|
||||||
case aeb_fate_opcodes:args(Op) of
|
case gmb_fate_opcodes:args(Op) of
|
||||||
0 ->
|
0 ->
|
||||||
{Rest, [OpName | Code]};
|
{Rest, [OpName | Code]};
|
||||||
N ->
|
N ->
|
||||||
@ -397,7 +397,7 @@ deserialize_n_args(N, <<M3:2, M2:2, M1:2, M0:2, Rest/binary>>) when N =< 4 ->
|
|||||||
stack ->
|
stack ->
|
||||||
{{stack, 0}, Acc};
|
{{stack, 0}, Acc};
|
||||||
Modifier ->
|
Modifier ->
|
||||||
{Arg, Acc2} = aeb_fate_encoding:deserialize_one(Acc),
|
{Arg, Acc2} = gmb_fate_encoding:deserialize_one(Acc),
|
||||||
{{Modifier, Arg}, Acc2}
|
{{Modifier, Arg}, Acc2}
|
||||||
end
|
end
|
||||||
end, Rest, ArgMods);
|
end, Rest, ArgMods);
|
||||||
@ -410,13 +410,13 @@ deserialize_n_args(N, <<M7:2, M6:2, M5:2, M4:2, M3:2, M2:2, M1:2, M0:2,
|
|||||||
stack ->
|
stack ->
|
||||||
{{stack, 0}, Acc};
|
{{stack, 0}, Acc};
|
||||||
Modifier ->
|
Modifier ->
|
||||||
{Arg, Acc2} = aeb_fate_encoding:deserialize_one(Acc),
|
{Arg, Acc2} = gmb_fate_encoding:deserialize_one(Acc),
|
||||||
{{Modifier, Arg}, Acc2}
|
{{Modifier, Arg}, Acc2}
|
||||||
end
|
end
|
||||||
end, Rest, ArgMods).
|
end, Rest, ArgMods).
|
||||||
|
|
||||||
deserialize_attributes(Binary) ->
|
deserialize_attributes(Binary) ->
|
||||||
{AttrVal, Rest} = aeb_fate_encoding:deserialize_one(Binary),
|
{AttrVal, Rest} = gmb_fate_encoding:deserialize_one(Binary),
|
||||||
Attrs = [ attr(AVal) || AVal <- attr_vals(1, AttrVal) ],
|
Attrs = [ attr(AVal) || AVal <- attr_vals(1, AttrVal) ],
|
||||||
{lists:sort(Attrs), Rest}.
|
{lists:sort(Attrs), Rest}.
|
||||||
|
|
||||||
@ -428,16 +428,16 @@ attr(1) -> private;
|
|||||||
attr(2) -> payable.
|
attr(2) -> payable.
|
||||||
|
|
||||||
deserialize_signature(Binary) ->
|
deserialize_signature(Binary) ->
|
||||||
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
{{tuple, Args}, Rest} = gmb_fate_encoding:deserialize_type(Binary),
|
||||||
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
{RetType, Rest2} = gmb_fate_encoding:deserialize_type(Rest),
|
||||||
{{Args, RetType}, Rest2}.
|
{{Args, RetType}, Rest2}.
|
||||||
|
|
||||||
deserialize_symbols(Table) ->
|
deserialize_symbols(Table) ->
|
||||||
?FATE_MAP_VALUE(SymbolTable) = aeb_fate_encoding:deserialize(Table),
|
?FATE_MAP_VALUE(SymbolTable) = gmb_fate_encoding:deserialize(Table),
|
||||||
SymbolTable.
|
SymbolTable.
|
||||||
|
|
||||||
deserialize_annotations(AnnotationsBin) ->
|
deserialize_annotations(AnnotationsBin) ->
|
||||||
?FATE_MAP_VALUE(Annotations) = aeb_fate_encoding:deserialize(AnnotationsBin),
|
?FATE_MAP_VALUE(Annotations) = gmb_fate_encoding:deserialize(AnnotationsBin),
|
||||||
Annotations.
|
Annotations.
|
||||||
|
|
||||||
assert_zero([]) ->
|
assert_zero([]) ->
|
@ -1,8 +1,9 @@
|
|||||||
%% FATE data representation.
|
%% FATE data representation.
|
||||||
%%
|
%%
|
||||||
-include("aeb_fate_data.hrl").
|
-include("gmb_fate_data.hrl").
|
||||||
|
|
||||||
-module(aeb_fate_data).
|
-module(gmb_fate_data).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-type fate_integer() :: ?FATE_INTEGER_T.
|
-type fate_integer() :: ?FATE_INTEGER_T.
|
||||||
-type fate_boolean() :: ?FATE_BOOLEAN_T.
|
-type fate_boolean() :: ?FATE_BOOLEAN_T.
|
||||||
@ -182,19 +183,19 @@ format(M) when ?IS_FATE_MAP(M) ->
|
|||||||
["{ ", format_kvs(maps:to_list(?FATE_MAP_VALUE(M))), " }"];
|
["{ ", format_kvs(maps:to_list(?FATE_MAP_VALUE(M))), " }"];
|
||||||
format(?FATE_BYTES(X)) -> ["#", base64:encode(X)];
|
format(?FATE_BYTES(X)) -> ["#", base64:encode(X)];
|
||||||
format(?FATE_ADDRESS(X)) ->
|
format(?FATE_ADDRESS(X)) ->
|
||||||
["@", aeser_api_encoder:encode(account_pubkey, X)];
|
["@", gmser_api_encoder:encode(account_pubkey, X)];
|
||||||
format(?FATE_CONTRACT(X)) ->
|
format(?FATE_CONTRACT(X)) ->
|
||||||
["@", aeser_api_encoder:encode(contract_pubkey, X)];
|
["@", gmser_api_encoder:encode(contract_pubkey, X)];
|
||||||
format(?FATE_ORACLE(X)) ->
|
format(?FATE_ORACLE(X)) ->
|
||||||
["@", aeser_api_encoder:encode(oracle_pubkey, X)];
|
["@", gmser_api_encoder:encode(oracle_pubkey, X)];
|
||||||
format(?FATE_ORACLE_Q(X)) ->
|
format(?FATE_ORACLE_Q(X)) ->
|
||||||
["@", aeser_api_encoder:encode(oracle_query_id, X)];
|
["@", gmser_api_encoder:encode(oracle_query_id, X)];
|
||||||
format(?FATE_CHANNEL(X)) ->
|
format(?FATE_CHANNEL(X)) ->
|
||||||
["@", aeser_api_encoder:encode(channel, X)];
|
["@", gmser_api_encoder:encode(channel, X)];
|
||||||
format(?FATE_TYPEREP(X)) ->
|
format(?FATE_TYPEREP(X)) ->
|
||||||
["'", io_lib:format("~p", [X])];
|
["'", io_lib:format("~p", [X])];
|
||||||
format(?FATE_CONTRACT_BYTEARRAY(B)) ->
|
format(?FATE_CONTRACT_BYTEARRAY(B)) ->
|
||||||
["@", aeser_api_encoder:encode(contract_bytearray, B)];
|
["@", gmser_api_encoder:encode(contract_bytearray, B)];
|
||||||
format(V) -> exit({not_a_fate_type, V}).
|
format(V) -> exit({not_a_fate_type, V}).
|
||||||
|
|
||||||
format_bits(0, Acc) -> Acc;
|
format_bits(0, Acc) -> Acc;
|
@ -29,7 +29,7 @@
|
|||||||
%% * First draft of FATE serialization encoding/decoding.
|
%% * First draft of FATE serialization encoding/decoding.
|
||||||
%% Initial experiment with tags
|
%% Initial experiment with tags
|
||||||
%% * Second draft
|
%% * Second draft
|
||||||
%% * FATE data is now defined in aefa_data.erl
|
%% * FATE data is now defined in gmfa_data.erl
|
||||||
%% * Third draft
|
%% * Third draft
|
||||||
%% * Added Bit strings
|
%% * Added Bit strings
|
||||||
%%
|
%%
|
||||||
@ -39,7 +39,8 @@
|
|||||||
%% * Handle instructions.
|
%% * Handle instructions.
|
||||||
%%
|
%%
|
||||||
%% ------------------------------------------------------------------------
|
%% ------------------------------------------------------------------------
|
||||||
-module(aeb_fate_encoding).
|
-module(gmb_fate_encoding).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ deserialize/1
|
-export([ deserialize/1
|
||||||
, deserialize_one/1
|
, deserialize_one/1
|
||||||
@ -52,7 +53,7 @@
|
|||||||
-export([sort/1]).
|
-export([sort/1]).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-include("aeb_fate_data.hrl").
|
-include("gmb_fate_data.hrl").
|
||||||
|
|
||||||
%% Definition of tag scheme.
|
%% Definition of tag scheme.
|
||||||
%% This has to follow the protocol specification.
|
%% This has to follow the protocol specification.
|
||||||
@ -135,7 +136,7 @@
|
|||||||
%% Serialized a Fate data value into a sequence of bytes
|
%% Serialized a Fate data value into a sequence of bytes
|
||||||
%% according to the Fate serialization specification.
|
%% according to the Fate serialization specification.
|
||||||
%% TODO: The type Fate Data is not final yet.
|
%% TODO: The type Fate Data is not final yet.
|
||||||
-spec serialize(aeb_fate_data:fate_type()) -> binary().
|
-spec serialize(gmb_fate_data:fate_type()) -> binary().
|
||||||
serialize(?FATE_TRUE) -> <<?TRUE>>;
|
serialize(?FATE_TRUE) -> <<?TRUE>>;
|
||||||
serialize(?FATE_FALSE) -> <<?FALSE>>;
|
serialize(?FATE_FALSE) -> <<?FALSE>>;
|
||||||
serialize(?FATE_UNIT) -> <<?EMPTY_TUPLE>>; %% ! Untyped
|
serialize(?FATE_UNIT) -> <<?EMPTY_TUPLE>>; %% ! Untyped
|
||||||
@ -158,15 +159,15 @@ serialize(String) when ?IS_FATE_STRING(String),
|
|||||||
serialize(?FATE_BYTES(Bytes)) when is_binary(Bytes) ->
|
serialize(?FATE_BYTES(Bytes)) when is_binary(Bytes) ->
|
||||||
<<?OBJECT, ?OTYPE_BYTES, (serialize(?FATE_STRING(Bytes)))/binary>>;
|
<<?OBJECT, ?OTYPE_BYTES, (serialize(?FATE_STRING(Bytes)))/binary>>;
|
||||||
serialize(?FATE_ADDRESS(Address)) when is_binary(Address) ->
|
serialize(?FATE_ADDRESS(Address)) when is_binary(Address) ->
|
||||||
<<?OBJECT, ?OTYPE_ADDRESS, (aeser_rlp:encode(Address))/binary>>;
|
<<?OBJECT, ?OTYPE_ADDRESS, (gmser_rlp:encode(Address))/binary>>;
|
||||||
serialize(?FATE_CONTRACT(Address)) when is_binary(Address) ->
|
serialize(?FATE_CONTRACT(Address)) when is_binary(Address) ->
|
||||||
<<?OBJECT, ?OTYPE_CONTRACT, (aeser_rlp:encode(Address))/binary>>;
|
<<?OBJECT, ?OTYPE_CONTRACT, (gmser_rlp:encode(Address))/binary>>;
|
||||||
serialize(?FATE_ORACLE(Address)) when is_binary(Address) ->
|
serialize(?FATE_ORACLE(Address)) when is_binary(Address) ->
|
||||||
<<?OBJECT, ?OTYPE_ORACLE, (aeser_rlp:encode(Address))/binary>>;
|
<<?OBJECT, ?OTYPE_ORACLE, (gmser_rlp:encode(Address))/binary>>;
|
||||||
serialize(?FATE_ORACLE_Q(Address)) when is_binary(Address) ->
|
serialize(?FATE_ORACLE_Q(Address)) when is_binary(Address) ->
|
||||||
<<?OBJECT, ?OTYPE_ORACLE_Q, (aeser_rlp:encode(Address))/binary>>;
|
<<?OBJECT, ?OTYPE_ORACLE_Q, (gmser_rlp:encode(Address))/binary>>;
|
||||||
serialize(?FATE_CHANNEL(Address)) when is_binary(Address) ->
|
serialize(?FATE_CHANNEL(Address)) when is_binary(Address) ->
|
||||||
<<?OBJECT, ?OTYPE_CHANNEL, (aeser_rlp:encode(Address))/binary>>;
|
<<?OBJECT, ?OTYPE_CHANNEL, (gmser_rlp:encode(Address))/binary>>;
|
||||||
serialize(?FATE_TUPLE(T)) when size(T) > 0 ->
|
serialize(?FATE_TUPLE(T)) when size(T) > 0 ->
|
||||||
S = size(T),
|
S = size(T),
|
||||||
L = tuple_to_list(T),
|
L = tuple_to_list(T),
|
||||||
@ -209,7 +210,7 @@ serialize(?FATE_VARIANT(Arities, Tag, Values)) ->
|
|||||||
, is_tuple(Values) ->
|
, is_tuple(Values) ->
|
||||||
Arity = lists:nth(Tag+1, Arities),
|
Arity = lists:nth(Tag+1, Arities),
|
||||||
if size(Values) =:= Arity ->
|
if size(Values) =:= Arity ->
|
||||||
EncodedArities = aeser_rlp:encode(list_to_binary(Arities)),
|
EncodedArities = gmser_rlp:encode(list_to_binary(Arities)),
|
||||||
<<?VARIANT,
|
<<?VARIANT,
|
||||||
EncodedArities/binary,
|
EncodedArities/binary,
|
||||||
Tag:8,
|
Tag:8,
|
||||||
@ -227,7 +228,7 @@ serialize(?FATE_CONTRACT_BYTEARRAY(B)) ->
|
|||||||
|
|
||||||
%% -----------------------------------------------------
|
%% -----------------------------------------------------
|
||||||
|
|
||||||
-spec serialize_type(aeb_fate_data:fate_type_type()) -> [byte()].
|
-spec serialize_type(gmb_fate_data:fate_type_type()) -> [byte()].
|
||||||
serialize_type(integer) -> [?TYPE_INTEGER];
|
serialize_type(integer) -> [?TYPE_INTEGER];
|
||||||
serialize_type(boolean) -> [?TYPE_BOOLEAN];
|
serialize_type(boolean) -> [?TYPE_BOOLEAN];
|
||||||
serialize_type(any) -> [?TYPE_ANY];
|
serialize_type(any) -> [?TYPE_ANY];
|
||||||
@ -238,6 +239,8 @@ serialize_type({tuple, Ts}) ->
|
|||||||
N when N =< 255 ->
|
N when N =< 255 ->
|
||||||
[?TYPE_TUPLE, N | [serialize_type(T) || T <- Ts]]
|
[?TYPE_TUPLE, N | [serialize_type(T) || T <- Ts]]
|
||||||
end;
|
end;
|
||||||
|
serialize_type({bytes, any}) ->
|
||||||
|
[?TYPE_BYTES | binary_to_list(serialize_integer(-1))];
|
||||||
serialize_type({bytes, N}) when 0 =< N ->
|
serialize_type({bytes, N}) when 0 =< N ->
|
||||||
[?TYPE_BYTES | binary_to_list(serialize_integer(N))];
|
[?TYPE_BYTES | binary_to_list(serialize_integer(N))];
|
||||||
serialize_type(address) -> [?TYPE_OBJECT, ?OTYPE_ADDRESS];
|
serialize_type(address) -> [?TYPE_OBJECT, ?OTYPE_ADDRESS];
|
||||||
@ -257,7 +260,7 @@ serialize_type({variant, ListOfVariants}) ->
|
|||||||
serialize_type(contract_bytearray) -> [?TYPE_CONTRACT_BYTEARRAY].
|
serialize_type(contract_bytearray) -> [?TYPE_CONTRACT_BYTEARRAY].
|
||||||
|
|
||||||
|
|
||||||
-spec deserialize_type(binary()) -> {aeb_fate_data:fate_type_type(), binary()}.
|
-spec deserialize_type(binary()) -> {gmb_fate_data:fate_type_type(), binary()}.
|
||||||
deserialize_type(<<?TYPE_INTEGER, Rest/binary>>) -> {integer, Rest};
|
deserialize_type(<<?TYPE_INTEGER, Rest/binary>>) -> {integer, Rest};
|
||||||
deserialize_type(<<?TYPE_BOOLEAN, Rest/binary>>) -> {boolean, Rest};
|
deserialize_type(<<?TYPE_BOOLEAN, Rest/binary>>) -> {boolean, Rest};
|
||||||
deserialize_type(<<?TYPE_ANY, Rest/binary>>) -> {any, Rest};
|
deserialize_type(<<?TYPE_ANY, Rest/binary>>) -> {any, Rest};
|
||||||
@ -270,8 +273,12 @@ deserialize_type(<<?TYPE_TUPLE, N, Rest/binary>>) ->
|
|||||||
{{tuple, Ts}, Rest2};
|
{{tuple, Ts}, Rest2};
|
||||||
deserialize_type(<<?TYPE_BYTES, Rest/binary>>) ->
|
deserialize_type(<<?TYPE_BYTES, Rest/binary>>) ->
|
||||||
{N, Rest2} = deserialize_one(Rest),
|
{N, Rest2} = deserialize_one(Rest),
|
||||||
true = is_integer(N) andalso N >= 0,
|
true = is_integer(N),
|
||||||
{{bytes, N}, Rest2};
|
if N == -1 ->
|
||||||
|
{{bytes, any}, Rest2};
|
||||||
|
0 =< N ->
|
||||||
|
{{bytes, N}, Rest2}
|
||||||
|
end;
|
||||||
deserialize_type(<<?TYPE_OBJECT, ObjectType, Rest/binary>>) ->
|
deserialize_type(<<?TYPE_OBJECT, ObjectType, Rest/binary>>) ->
|
||||||
case ObjectType of
|
case ObjectType of
|
||||||
?OTYPE_ADDRESS -> {address, Rest};
|
?OTYPE_ADDRESS -> {address, Rest};
|
||||||
@ -310,13 +317,13 @@ deserialize_types(N, Binary, Acc) ->
|
|||||||
%% -----------------------------------------------------
|
%% -----------------------------------------------------
|
||||||
|
|
||||||
rlp_encode_int(S) when S >= 0 ->
|
rlp_encode_int(S) when S >= 0 ->
|
||||||
aeser_rlp:encode(binary:encode_unsigned(S)).
|
gmser_rlp:encode(binary:encode_unsigned(S)).
|
||||||
|
|
||||||
|
|
||||||
%% first byte of the binary gives the number of bytes we need <<129>> is 1, <<130>> = 2,
|
%% first byte of the binary gives the number of bytes we need <<129>> is 1, <<130>> = 2,
|
||||||
%% so <<129, 0>> is <<0>> and <<130, 0, 0>> is <<0, 0>>
|
%% so <<129, 0>> is <<0>> and <<130, 0, 0>> is <<0, 0>>
|
||||||
rlp_decode_int(Binary) ->
|
rlp_decode_int(Binary) ->
|
||||||
{Bin1, Rest} = aeser_rlp:decode_one(Binary),
|
{Bin1, Rest} = gmser_rlp:decode_one(Binary),
|
||||||
Int = binary:decode_unsigned(Bin1),
|
Int = binary:decode_unsigned(Bin1),
|
||||||
ReEncode = rlp_encode_int(Int),
|
ReEncode = rlp_encode_int(Int),
|
||||||
case <<ReEncode/binary, Rest/binary>> == Binary of
|
case <<ReEncode/binary, Rest/binary>> == Binary of
|
||||||
@ -347,7 +354,7 @@ serialize_bits(B) when is_integer(B) ->
|
|||||||
B >= 0 -> <<?POS_BITS, (rlp_encode_int(Abs))/binary>>
|
B >= 0 -> <<?POS_BITS, (rlp_encode_int(Abs))/binary>>
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec deserialize(binary()) -> aeb_fate_data:fate_type().
|
-spec deserialize(binary()) -> gmb_fate_data:fate_type().
|
||||||
deserialize(B) ->
|
deserialize(B) ->
|
||||||
{T, <<>>} = deserialize2(B),
|
{T, <<>>} = deserialize2(B),
|
||||||
T.
|
T.
|
||||||
@ -400,7 +407,7 @@ deserialize2(<<?OBJECT, ?OTYPE_BYTES, Rest/binary>>) ->
|
|||||||
true = ?IS_FATE_STRING(String),
|
true = ?IS_FATE_STRING(String),
|
||||||
{?FATE_BYTES(?FATE_STRING_VALUE(String)), Rest2};
|
{?FATE_BYTES(?FATE_STRING_VALUE(String)), Rest2};
|
||||||
deserialize2(<<?OBJECT, ObjectType, Rest/binary>>) ->
|
deserialize2(<<?OBJECT, ObjectType, Rest/binary>>) ->
|
||||||
{A, Rest2} = aeser_rlp:decode_one(Rest),
|
{A, Rest2} = gmser_rlp:decode_one(Rest),
|
||||||
Val =
|
Val =
|
||||||
case ObjectType of
|
case ObjectType of
|
||||||
?OTYPE_ADDRESS -> ?FATE_ADDRESS(A);
|
?OTYPE_ADDRESS -> ?FATE_ADDRESS(A);
|
||||||
@ -449,7 +456,7 @@ deserialize2(<<?MAP_ID, Rest/binary>>) ->
|
|||||||
{Id, Rest1} = rlp_decode_int(Rest),
|
{Id, Rest1} = rlp_decode_int(Rest),
|
||||||
{?FATE_STORE_MAP(#{}, Id), Rest1};
|
{?FATE_STORE_MAP(#{}, Id), Rest1};
|
||||||
deserialize2(<<?VARIANT, Rest/binary>>) ->
|
deserialize2(<<?VARIANT, Rest/binary>>) ->
|
||||||
{AritiesBin, <<Tag:8, Rest2/binary>>} = aeser_rlp:decode_one(Rest),
|
{AritiesBin, <<Tag:8, Rest2/binary>>} = gmser_rlp:decode_one(Rest),
|
||||||
Arities = binary_to_list(AritiesBin),
|
Arities = binary_to_list(AritiesBin),
|
||||||
Size = length(Arities),
|
Size = length(Arities),
|
||||||
if Tag > Size -> exit({too_large_tag_in_variant, Tag, Size});
|
if Tag > Size -> exit({too_large_tag_in_variant, Tag, Size});
|
||||||
@ -496,7 +503,7 @@ sort_and_check(List) ->
|
|||||||
|
|
||||||
sort(KVList) ->
|
sort(KVList) ->
|
||||||
SortFun = fun({K1, _}, {K2, _}) ->
|
SortFun = fun({K1, _}, {K2, _}) ->
|
||||||
aeb_fate_data:elt(K1, K2)
|
gmb_fate_data:elt(K1, K2)
|
||||||
end,
|
end,
|
||||||
lists:sort(SortFun, KVList).
|
lists:sort(SortFun, KVList).
|
||||||
|
|
133
src/gmb_fate_generate_docs.erl
Normal file
133
src/gmb_fate_generate_docs.erl
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
-module(gmb_fate_generate_docs).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
|
-export([generate_documentation/2, generate_documentation/3]).
|
||||||
|
|
||||||
|
-export(
|
||||||
|
[ gen_protocol_opcodes_flags_and_gas/1
|
||||||
|
, gen_protocol_description_of_operations/1
|
||||||
|
, gen_protocol_opcodes/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
-define(LIMA_PROTOCOL_VSN, 4).
|
||||||
|
-define(IRIS_PROTOCOL_VSN, 5).
|
||||||
|
|
||||||
|
generate_documentation(Filename, Fields) ->
|
||||||
|
generate_documentation(Filename, Fields, fun(_) -> true end).
|
||||||
|
generate_documentation(Filename, Fields, Filter) when is_function(Filter, 1) ->
|
||||||
|
{ok, File} = file:open(Filename, [write, {encoding, utf8}]),
|
||||||
|
Header =
|
||||||
|
lists:flatten(
|
||||||
|
"|" ++ [" " ++ header_name(F) ++ " |" || F <- Fields] ++ "\n"
|
||||||
|
),
|
||||||
|
Separator =
|
||||||
|
lists:flatten(
|
||||||
|
"|" ++ [" " ++ ["-" || _ <- header_name(F)] ++ " |" || F <- Fields] ++ "\n"
|
||||||
|
),
|
||||||
|
Instructions =
|
||||||
|
lists:flatten(
|
||||||
|
[gen_doc_for_op(Op, Fields)
|
||||||
|
++ "\n" || Op <- gmb_fate_generate_ops:get_ops(), Filter(Op)]),
|
||||||
|
io:format(File, "~ts~ts~ts\n", [Header, Separator, Instructions]),
|
||||||
|
file:close(File).
|
||||||
|
|
||||||
|
header_name(opname) ->
|
||||||
|
"Name";
|
||||||
|
header_name(opcode) ->
|
||||||
|
"Opcode";
|
||||||
|
header_name(arity) ->
|
||||||
|
"Arity";
|
||||||
|
header_name(end_bb) ->
|
||||||
|
"Ends basic block";
|
||||||
|
header_name(in_auth) ->
|
||||||
|
"Allowed in auth";
|
||||||
|
header_name(offchain) ->
|
||||||
|
"Allowed offchain";
|
||||||
|
header_name(format) ->
|
||||||
|
"Args";
|
||||||
|
header_name(doc) ->
|
||||||
|
"Description";
|
||||||
|
header_name(gas) ->
|
||||||
|
"Gas cost";
|
||||||
|
header_name(arg_types) ->
|
||||||
|
"Arg types";
|
||||||
|
header_name(res_type) ->
|
||||||
|
"Res type".
|
||||||
|
|
||||||
|
gen_doc_for_op(#{ opname := OpName
|
||||||
|
, opcode := OpCode
|
||||||
|
, arity := Arity
|
||||||
|
, end_bb := EndBB
|
||||||
|
, in_auth := InAuth
|
||||||
|
, offchain := AllowedOffchain
|
||||||
|
, format := FateFormat
|
||||||
|
, doc := Doc
|
||||||
|
, gas := Gas
|
||||||
|
, arg_types := ArgTypes
|
||||||
|
, res_type := ResType
|
||||||
|
}, Fields) ->
|
||||||
|
"| " ++
|
||||||
|
string:join(
|
||||||
|
[ case Field of
|
||||||
|
opname -> io_lib:format("`~s`", [OpName]);
|
||||||
|
opcode -> io_lib:format("0x~.16b", [OpCode]);
|
||||||
|
arity -> io_lib:format("~p", [Arity]);
|
||||||
|
end_bb -> io_lib:format("~p", [EndBB]);
|
||||||
|
in_auth -> io_lib:format("~p", [InAuth]);
|
||||||
|
offchain -> io_lib:format("~p", [AllowedOffchain]);
|
||||||
|
format ->
|
||||||
|
case FateFormat of
|
||||||
|
[] -> "";
|
||||||
|
_ -> lists:join(
|
||||||
|
" ",
|
||||||
|
[format_arg_doc(A) ||
|
||||||
|
A <-
|
||||||
|
lists:zip(FateFormat,
|
||||||
|
lists:seq(0,length(FateFormat)-1))])
|
||||||
|
end;
|
||||||
|
doc -> Doc;
|
||||||
|
gas when is_integer(Gas) -> io_lib:format("~p", [Gas]);
|
||||||
|
gas when is_list(Gas) ->
|
||||||
|
lists:flatten(
|
||||||
|
string:join(
|
||||||
|
[ io_lib:format(
|
||||||
|
"~p (~s)",
|
||||||
|
[GasVal, protocol_name(Prot)]
|
||||||
|
)
|
||||||
|
|| {Prot, GasVal} <- Gas
|
||||||
|
], ", "));
|
||||||
|
arg_types -> io_lib:format("~p", [ArgTypes]);
|
||||||
|
res_type -> io_lib:format("~p", [ResType])
|
||||||
|
end
|
||||||
|
|| Field <- Fields
|
||||||
|
],
|
||||||
|
" | ") ++ " |".
|
||||||
|
|
||||||
|
protocol_name(?LIMA_PROTOCOL_VSN) ->
|
||||||
|
"lima";
|
||||||
|
protocol_name(?IRIS_PROTOCOL_VSN) ->
|
||||||
|
"iris".
|
||||||
|
|
||||||
|
format_arg_doc({a, N}) -> io_lib:format("Arg~w", [N]);
|
||||||
|
format_arg_doc({is,_N}) -> "Identifier";
|
||||||
|
format_arg_doc({ii,_N}) -> "Integer";
|
||||||
|
format_arg_doc({li,_N}) -> "[Integers]";
|
||||||
|
format_arg_doc({t,_N}) -> "Type".
|
||||||
|
|
||||||
|
|
||||||
|
%% --- protocol documentation ---
|
||||||
|
|
||||||
|
gen_protocol_description_of_operations(Filename) ->
|
||||||
|
generate_documentation(
|
||||||
|
Filename, [opname, format, doc, arg_types, res_type]
|
||||||
|
).
|
||||||
|
|
||||||
|
gen_protocol_opcodes_flags_and_gas(Filename) ->
|
||||||
|
generate_documentation(
|
||||||
|
Filename, [opcode, opname, end_bb, in_auth, offchain, gas]
|
||||||
|
).
|
||||||
|
|
||||||
|
gen_protocol_opcodes(Filename) ->
|
||||||
|
generate_documentation(
|
||||||
|
Filename, [opcode, opname]
|
||||||
|
).
|
@ -1,8 +1,8 @@
|
|||||||
-module(aeb_fate_generate_ops).
|
-module(gmb_fate_generate_ops).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ gen_and_halt/1
|
-export([ gen_and_halt/1
|
||||||
, generate/0
|
, generate/0
|
||||||
, generate_documentation/1
|
|
||||||
, get_ops/0
|
, get_ops/0
|
||||||
, test_asm_generator/1 ]).
|
, test_asm_generator/1 ]).
|
||||||
|
|
||||||
@ -19,12 +19,12 @@ generate(Src, Include) ->
|
|||||||
check_defs(ops_defs()),
|
check_defs(ops_defs()),
|
||||||
Ops = get_ops(),
|
Ops = get_ops(),
|
||||||
%% io:format("ops: ~p\n", [Ops]),
|
%% io:format("ops: ~p\n", [Ops]),
|
||||||
HrlFile = Include ++ "aeb_fate_opcodes.hrl",
|
HrlFile = Include ++ "gmb_fate_opcodes.hrl",
|
||||||
generate_header_file(HrlFile, Ops),
|
generate_header_file(HrlFile, Ops),
|
||||||
generate_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops),
|
generate_opcodes_ops(gmb_fate_opcodes, HrlFile, Src, Ops),
|
||||||
generate_code_ops(aeb_fate_ops, Src, Ops),
|
generate_code_ops(gmb_fate_ops, Src, Ops),
|
||||||
generate_scanner("aeb_fate_asm_scan.template", "aeb_fate_asm_scan.xrl", Src, Ops),
|
generate_scanner("gmb_fate_asm_scan.template", "gmb_fate_asm_scan.xrl", Src, Ops),
|
||||||
gen_asm_pp(aeb_fate_pp, Src, Ops).
|
gen_asm_pp(gmb_fate_pp, Src, Ops).
|
||||||
|
|
||||||
check_defs(List) ->
|
check_defs(List) ->
|
||||||
true = check_numbering(0, lists:keysort(2, List)).
|
true = check_numbering(0, lists:keysort(2, List)).
|
||||||
@ -32,7 +32,11 @@ check_defs(List) ->
|
|||||||
check_numbering(N, [T|Rest]) ->
|
check_numbering(N, [T|Rest]) ->
|
||||||
OpCode = element(2, T),
|
OpCode = element(2, T),
|
||||||
case OpCode of
|
case OpCode of
|
||||||
N -> check_numbering(N+1, Rest);
|
N -> check_numbering(N+1, Rest);
|
||||||
|
16#6d -> check_numbering(16#6d+1, Rest); %% Oracles
|
||||||
|
16#7b -> check_numbering(16#7b+1, Rest); %% Oracles
|
||||||
|
16#9b -> check_numbering(16#9b+1, Rest); %% Oracles
|
||||||
|
16#f0 -> check_numbering(16#f0+1, Rest);
|
||||||
16#fa -> check_numbering(16#fa+1, Rest);
|
16#fa -> check_numbering(16#fa+1, Rest);
|
||||||
_ when OpCode < N -> {duplicate_opcode, OpCode};
|
_ when OpCode < N -> {duplicate_opcode, OpCode};
|
||||||
_ when OpCode > N -> {missing_opcode, N}
|
_ when OpCode > N -> {missing_opcode, N}
|
||||||
@ -46,7 +50,7 @@ check_numbering(_, []) -> true.
|
|||||||
-define(GAS_IRIS(A, B), [{?IRIS_PROTOCOL_VSN, B}, {?LIMA_PROTOCOL_VSN, A}]).
|
-define(GAS_IRIS(A, B), [{?IRIS_PROTOCOL_VSN, B}, {?LIMA_PROTOCOL_VSN, A}]).
|
||||||
|
|
||||||
ops_defs() ->
|
ops_defs() ->
|
||||||
%% Opname, Opcode, end_bb, in_auth offchain, gas, format, Constructor, ArgType, ResType, Documentation
|
%% Opname, Opcode, end_bb, in_auth,offchain, gas, format, Constructor, ArgType, ResType, Documentation
|
||||||
[ { 'RETURN', 16#00, true, true, true, ?GAS(10), [], return, {}, any, "Return from function call, top of stack is return value . The type of the retun value has to match the return type of the function."}
|
[ { 'RETURN', 16#00, true, true, true, ?GAS(10), [], return, {}, any, "Return from function call, top of stack is return value . The type of the retun value has to match the return type of the function."}
|
||||||
, { 'RETURNR', 16#01, true, true, true, ?GAS(10), [a], returnr, {any}, any, "Push Arg0 and return from function. The type of the retun value has to match the return type of the function."}
|
, { 'RETURNR', 16#01, true, true, true, ?GAS(10), [a], returnr, {any}, any, "Push Arg0 and return from function. The type of the retun value has to match the return type of the function."}
|
||||||
, { 'CALL', 16#02, true, true, true, ?GAS(10), [a], call, {string}, any, "Call the function Arg0 with args on stack. The types of the arguments has to match the argument typs of the function."}
|
, { 'CALL', 16#02, true, true, true, ?GAS(10), [a], call, {string}, any, "Call the function Arg0 with args on stack. The types of the arguments has to match the argument typs of the function."}
|
||||||
@ -151,13 +155,8 @@ ops_defs() ->
|
|||||||
, { 'LOG4', 16#64, false, true, true, ?GAS(1400), [a,a,a,a,a], log, {integer, integer, integer, integer, string}, none, "Create a log message with four topics in the call object."}
|
, { 'LOG4', 16#64, false, true, true, ?GAS(1400), [a,a,a,a,a], log, {integer, integer, integer, integer, string}, none, "Create a log message with four topics in the call object."}
|
||||||
%% Transaction ops
|
%% Transaction ops
|
||||||
, { 'SPEND', 16#65, false, false, true, ?GAS_IRIS(100, 5000), [a,a], spend, {address, integer}, none, "Transfer Arg1 tokens to account Arg0. (If the contract account has at least that many tokens."}
|
, { 'SPEND', 16#65, false, false, true, ?GAS_IRIS(100, 5000), [a,a], spend, {address, integer}, none, "Transfer Arg1 tokens to account Arg0. (If the contract account has at least that many tokens."}
|
||||||
, { 'ORACLE_REGISTER', 16#66, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a,a,a,a,a], oracle_register, {signature, address, integer, variant, typerep, typerep}, oracle, "Arg0 := New oracle with address Arg2, query fee Arg3, TTL Arg4, query type Arg5 and response type Arg6. Arg0 contains delegation signature."}
|
%% Intentional gap (was oracles)
|
||||||
, { 'ORACLE_QUERY', 16#67, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a,a,a,a,a,a], oracle_query, {oracle, any, integer, variant, variant, typerep, typerep}, oracle_query, "Arg0 := New oracle query for oracle Arg1, question in Arg2, query fee in Arg3, query TTL in Arg4, response TTL in Arg5. Typereps for checking oracle type is in Arg6 and Arg7."}
|
|
||||||
, { 'ORACLE_RESPOND', 16#68, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a,a,a,a], oracle_respond, {signature, oracle, oracle_query,any, typerep, typerep}, none, "Respond as oracle Arg1 to query in Arg2 with response Arg3. Arg0 contains delegation signature. Typereps for checking oracle type is in Arg4 and Arg5."}
|
|
||||||
, { 'ORACLE_EXTEND', 16#69, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a], oracle_extend, {signature, oracle, variant}, none, "Extend oracle in Arg1 with TTL in Arg2. Arg0 contains delegation signature."}
|
|
||||||
, { 'ORACLE_GET_ANSWER', 16#6a, false, false, true, ?GAS_IRIS(100, 2000), [a,a,a,a,a], oracle_get_answer, {oracle, oracle_query, typerep, typerep}, any, "Arg0 := option variant with answer (if any) from oracle query in Arg1 given by oracle Arg0. Typereps for checking oracle type is in Arg3 and Arg4."}
|
|
||||||
, { 'ORACLE_GET_QUESTION', 16#6b, false, false, true, ?GAS_IRIS(100, 2000), [a,a,a,a,a], oracle_get_question, {oracle, oracle_query, typerep, typerep}, any, "Arg0 := question in oracle query Arg2 given to oracle Arg1. Typereps for checking oracle type is in Arg3 and Arg4."}
|
|
||||||
, { 'ORACLE_QUERY_FEE', 16#6c, false, false, true, ?GAS_IRIS(100, 2000), [a,a], oracle_query_fee, {oracle}, integer, "Arg0 := query fee for oracle Arg1"}
|
|
||||||
, { 'AENS_RESOLVE', 16#6d, false, false, true, ?GAS_IRIS(100, 2000), [a,a,a,a], aens_resolve, {string, string, typerep}, variant, "Resolve name in Arg0 with tag Arg1. Arg2 describes the type parameter of the resolved name."}
|
, { 'AENS_RESOLVE', 16#6d, false, false, true, ?GAS_IRIS(100, 2000), [a,a,a,a], aens_resolve, {string, string, typerep}, variant, "Resolve name in Arg0 with tag Arg1. Arg2 describes the type parameter of the resolved name."}
|
||||||
, { 'AENS_PRECLAIM', 16#6e, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a], aens_preclaim, {signature, address, hash}, none, "Preclaim the hash in Arg2 for address in Arg1. Arg0 contains delegation signature."}
|
, { 'AENS_PRECLAIM', 16#6e, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a], aens_preclaim, {signature, address, hash}, none, "Preclaim the hash in Arg2 for address in Arg1. Arg0 contains delegation signature."}
|
||||||
, { 'AENS_CLAIM', 16#6f, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a,a,a], aens_claim, {signature, address, string, integer, integer}, none, "Attempt to claim the name in Arg2 for address in Arg1 at a price in Arg4. Arg3 contains the salt used to hash the preclaim. Arg0 contains delegation signature."}
|
, { 'AENS_CLAIM', 16#6f, false, false, false, ?GAS_IRIS(100, 10000), [a,a,a,a,a], aens_claim, {signature, address, string, integer, integer}, none, "Attempt to claim the name in Arg2 for address in Arg1 at a price in Arg4. Arg3 contains the salt used to hash the preclaim. Arg0 contains delegation signature."}
|
||||||
@ -172,10 +171,8 @@ ops_defs() ->
|
|||||||
, { 'CONTRACT_TO_ADDRESS', 16#76, false, true, true, ?GAS(10), [a,a], contract_to_address, {contract}, address, "Arg0 := Arg1 - A no-op type conversion"}
|
, { 'CONTRACT_TO_ADDRESS', 16#76, false, true, true, ?GAS(10), [a,a], contract_to_address, {contract}, address, "Arg0 := Arg1 - A no-op type conversion"}
|
||||||
, { 'AUTH_TX_HASH', 16#77, false, true, true, ?GAS(10), [a], auth_tx_hash, {}, variant, "If in GA authentication context return Some(TxHash) otherwise None."}
|
, { 'AUTH_TX_HASH', 16#77, false, true, true, ?GAS(10), [a], auth_tx_hash, {}, variant, "If in GA authentication context return Some(TxHash) otherwise None."}
|
||||||
|
|
||||||
, { 'ORACLE_CHECK', 16#78, false, false, true, ?GAS(100), [a,a,a,a], oracle_check, {oracle, typerep, typerep}, bool, "Arg0 := is Arg1 an oracle with the given query (Arg2) and response (Arg3) types"}
|
%% Intentional gap (was oracles)
|
||||||
, { 'ORACLE_CHECK_QUERY', 16#79, false, false, true, ?GAS(100), [a,a,a,a,a], oracle_check_query, {oracle, oracle_query, typerep, typerep}, bool, "Arg0 := is Arg2 a query for the oracle Arg1 with the given types (Arg3, Arg4)"}
|
|
||||||
|
|
||||||
, { 'IS_ORACLE', 16#7a, false, false, true, ?GAS(100), [a,a], is_oracle, {address}, bool, "Arg0 := is Arg1 an oracle"}
|
|
||||||
, { 'IS_CONTRACT', 16#7b, false, false, true, ?GAS(100), [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
, { 'IS_CONTRACT', 16#7b, false, false, true, ?GAS(100), [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
||||||
, { 'IS_PAYABLE', 16#7c, false, false, true, ?GAS(100), [a,a], is_payable, {address}, bool, "Arg0 := is Arg1 a payable address"}
|
, { 'IS_PAYABLE', 16#7c, false, false, true, ?GAS(100), [a,a], is_payable, {address}, bool, "Arg0 := is Arg1 a payable address"}
|
||||||
, { 'CREATOR', 16#7d, false, true, true, ?GAS(10), [a], contract_creator, {}, address, "Arg0 := contract creator"}
|
, { 'CREATOR', 16#7d, false, true, true, ?GAS(10), [a], contract_creator, {}, address, "Arg0 := contract creator"}
|
||||||
@ -214,7 +211,9 @@ ops_defs() ->
|
|||||||
, { 'BLS12_381_FP_TO_INT', 16#98, false, true, true, ?GAS(30), [a,a], bls12_381_fp_to_int, {tuple}, tuple, "Arg0 := from_montgomery(Arg1) - Convert montgomery representation (48 bytes) to integer"}
|
, { 'BLS12_381_FP_TO_INT', 16#98, false, true, true, ?GAS(30), [a,a], bls12_381_fp_to_int, {tuple}, tuple, "Arg0 := from_montgomery(Arg1) - Convert montgomery representation (48 bytes) to integer"}
|
||||||
|
|
||||||
, { 'AENS_LOOKUP', 16#99, false, false, true, ?GAS(2000), [a,a], aens_lookup, {string}, variant, "Lookup the name of Arg0. Returns option(AENS.name)"}
|
, { 'AENS_LOOKUP', 16#99, false, false, true, ?GAS(2000), [a,a], aens_lookup, {string}, variant, "Lookup the name of Arg0. Returns option(AENS.name)"}
|
||||||
, { 'ORACLE_EXPIRY', 16#9a, false, false, true, ?GAS(2000), [a,a], oracle_expiry, {oracle}, int, "Arg0 := expiry block for oracle Arg1"}
|
|
||||||
|
%% Intentional gap (was oracles)
|
||||||
|
|
||||||
, { 'AUTH_TX', 16#9b, false, true, true, ?GAS(100 ), [a], auth_tx, {}, variant, "If in GA authentication context return Some(Tx) otherwise None."}
|
, { 'AUTH_TX', 16#9b, false, true, true, ?GAS(100 ), [a], auth_tx, {}, variant, "If in GA authentication context return Some(Tx) otherwise None."}
|
||||||
|
|
||||||
, { 'STR_TO_LIST', 16#9c, false, true, true, ?GAS(100), [a,a], str_to_list, {string}, list, "Arg0 := string converted to list of characters"}
|
, { 'STR_TO_LIST', 16#9c, false, true, true, ?GAS(100), [a,a], str_to_list, {string}, list, "Arg0 := string converted to list of characters"}
|
||||||
@ -226,13 +225,34 @@ ops_defs() ->
|
|||||||
|
|
||||||
, { 'CALL_PGR', 16#a2, true, false, true, ?GAS(100), [a,is,a,a,a,a,a], call_pgr, {contract, string, typerep, typerep, integer, integer, bool}, variant, "Potentially protected remote call. Arg5 is protected flag, otherwise as CALL_GR."}
|
, { 'CALL_PGR', 16#a2, true, false, true, ?GAS(100), [a,is,a,a,a,a,a], call_pgr, {contract, string, typerep, typerep, integer, integer, bool}, variant, "Potentially protected remote call. Arg5 is protected flag, otherwise as CALL_GR."}
|
||||||
|
|
||||||
, { 'CREATE', 16#a3, true, false, true, ?GAS(10000), [a,a,a], create, {contract_bytearray, typerep, integer}, contract, "Deploys a contract with a bytecode Arg1 and value Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract address to stack top."}
|
, { 'CREATE', 16#a3, true, false, true, ?GAS(10000), [a,a,a], create, {contract_bytearray, typerep, integer}, contract, "Deploys a contract with a bytecode Arg1 and value Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract address to the top of the accumulator stack. If an account on the resulting address did exist before the call, the `payable` flag will be updated."}
|
||||||
, { 'CLONE', 16#a4, true, false, true, ?GAS(5000), [a,a,a,a], clone, {contract, typerep, integer, bool}, any, "Clones the contract under Arg1 and deploys it with value of Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract (or `None` on fail when protected) to stack top."}
|
, { 'CLONE', 16#a4, true, false, true, ?GAS(5000), [a,a,a,a], clone, {contract, typerep, integer, bool}, any, "Clones the contract under Arg1 and deploys it with value of Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract (or `None` on fail when protected) to the top of the accumulator stack. Does not copy the existing contract's store – it will be initialized by a fresh call to the `init` function. If an account on the resulting address did exist before the call, the `payable` flag will be updated."}
|
||||||
, { 'CLONE_G', 16#a5, true, false, true, ?GAS(5000), [a,a,a,a,a], clone_g, {contract, typerep, integer, integer, bool}, any, "Like `CLONE` but additionally limits gas of `init` call to Arg3"}
|
, { 'CLONE_G', 16#a5, true, false, true, ?GAS(5000), [a,a,a,a,a], clone_g, {contract, typerep, integer, integer, bool}, any, "Like `CLONE` but additionally limits the gas of the `init` call by Arg3"}
|
||||||
, { 'BYTECODE_HASH', 16#a6, false, true, true, ?GAS(100), [a,a], bytecode_hash, {contract}, variant, "Arg0 := hash of the deserialized contract's bytecode under address given in Arg1 (or `None` on fail)."}
|
, { 'BYTECODE_HASH', 16#a6, false, true, true, ?GAS(100), [a,a], bytecode_hash, {contract}, variant, "Arg0 := hash of the deserialized contract's bytecode under address given in Arg1 (or `None` on fail). Fails on AEVM contracts and contracts deployed before Iris."}
|
||||||
|
|
||||||
, { 'FEE', 16#a7, false, true, true, ?GAS(10), [a], fee, {}, integer, "Arg0 := The fee for the current call tx."}
|
, { 'FEE', 16#a7, false, true, true, ?GAS(10), [a], fee, {}, integer, "Arg0 := The fee for the current call tx."}
|
||||||
|
|
||||||
|
, { 'ADDRESS_TO_BYTES', 16#a8, false, true, true, ?GAS(10), [a, a], addr_to_bytes, {address}, bytes, "Arg0 := the byte representation of the address"}
|
||||||
|
, { 'POSEIDON', 16#a9, false, true, true, ?GAS(6000), [a, a, a], poseidon, {integer, integer}, integer, "Arg0 := the Poseidon hash of Arg1 and Arg2 - all integers in the BLS12-381 scalar field"}
|
||||||
|
, { 'MULMOD', 16#aa, false, true, true, ?GAS(10), [a, a, a, a], mulmod, {integer, integer, integer}, integer, "Arg0 := (Arg1 * Arg2) mod Arg3"}
|
||||||
|
, { 'BAND', 16#ab, false, true, true, ?GAS(10), [a, a, a], bin_and, {integer, integer}, integer, "Arg0 := Arg1 & Arg2"}
|
||||||
|
, { 'BOR', 16#ac, false, true, true, ?GAS(10), [a, a, a], bin_or, {integer, integer}, integer, "Arg0 := Arg1 | Arg2"}
|
||||||
|
, { 'BXOR', 16#ad, false, true, true, ?GAS(10), [a, a, a], bin_xor, {integer, integer}, integer, "Arg0 := Arg1 ^ Arg2"}
|
||||||
|
, { 'BNOT', 16#ae, false, true, true, ?GAS(10), [a, a], bin_not, {integer}, integer, "Arg0 := ~Arg1"}
|
||||||
|
, { 'BSL', 16#af, false, true, true, ?GAS(10), [a, a, a], bin_sl, {integer, integer}, integer, "Arg0 := Arg1 << Arg2"}
|
||||||
|
, { 'BSR', 16#b0, false, true, true, ?GAS(10), [a, a, a], bin_sr, {integer, integer}, integer, "Arg0 := Arg1 >> Arg2"}
|
||||||
|
, { 'BYTES_SPLIT_ANY', 16#b1, false, true, true, ?GAS(10), [a, a, a], bytes_split_any, {bytes, integer}, variant, "Arg0 := bytes_split_any(Arg1, Arg2), where a positive Arg2 is the length of the first chunk, and a negative Arg2 is the length of the second chunk. Returns None if byte array is not long enough."}
|
||||||
|
, { 'BYTES_SIZE', 16#b2, false, true, true, ?GAS(10), [a, a], bytes_size, {bytes}, integer, "Arg0 := bytes_size(Arg1), returns the number of bytes in the byte array."}
|
||||||
|
, { 'BYTES_TO_FIXED_SIZE', 16#b3, false, true, true, ?GAS(10), [a, a, a], bytes_to_fixed_size, {bytes, integer}, variant, "Arg0 := bytes_to_fixed_size(Arg1, Arg2), returns Some(Arg1') if byte_size(Arg1) == Arg2, None otherwise. The type of Arg1' is bytes(Arg2) but the value is unchanged"}
|
||||||
|
, { 'INT_TO_BYTES', 16#b4, false, true, true, ?GAS(10), [a, a, a], int_to_bytes, {integer, integer}, bytes, "Arg0 := turn integer Arg1 into a byte array (big endian) length Arg2 (truncating if not fit)."}
|
||||||
|
, { 'STR_TO_BYTES', 16#b5, false, true, true, ?GAS(10), [a, a], str_to_bytes, {integer}, bytes, "Arg0 := turn string Arg1 into the corresponding byte array."}
|
||||||
|
, { 'NETWORK_ID', 16#b6, false, true, true, ?GAS(10), [a], network_id, {}, string, "Arg0 := The network_id of the chain."}
|
||||||
|
|
||||||
|
, { 'DBG_LOC', 16#f0, false, true, true, ?GAS(0), [a, a], dbg_loc, {string, integer}, none, "Debug Op: Execution location. Args = {file_name, line_num}" }
|
||||||
|
, { 'DBG_DEF', 16#f1, false, true, true, ?GAS(0), [a, a], dbg_def, {string, any}, none, "Debug Op: Define a variable. Args = {var_name, register}" }
|
||||||
|
, { 'DBG_UNDEF', 16#f2, false, true, true, ?GAS(0), [a, a], dbg_undef, {string, any}, none, "Debug Op: Undefine a variable. Args = {var_name, register}" }
|
||||||
|
, { 'DBG_CONTRACT', 16#f3, false, true, true, ?GAS(0), [a], dbg_contract, {string}, none, "Debug Op: Name the current contract. Args: {contract_name}"}
|
||||||
|
|
||||||
, { 'DEACTIVATE', 16#fa, false, true, true, ?GAS(10), [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
, { 'DEACTIVATE', 16#fa, false, true, true, ?GAS(10), [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
||||||
, { 'ABORT', 16#fb, true, true, true, ?GAS(10), [a], abort, {string}, none, "Abort execution (dont use all gas) with error message in Arg0."}
|
, { 'ABORT', 16#fb, true, true, true, ?GAS(10), [a], abort, {string}, none, "Abort execution (dont use all gas) with error message in Arg0."}
|
||||||
, { 'EXIT', 16#fc, true, true, true, ?GAS(10), [a], exit, {string}, none, "Abort execution (use upp all gas) with error message in Arg0."}
|
, { 'EXIT', 16#fc, true, true, true, ?GAS(10), [a], exit, {string}, none, "Abort execution (use upp all gas) with error message in Arg0."}
|
||||||
@ -314,7 +334,7 @@ generate_code_ops(Modulename, SrcDir, Ops) ->
|
|||||||
" and documentation for Fate "
|
" and documentation for Fate "
|
||||||
"instructions.\n")]),
|
"instructions.\n")]),
|
||||||
io:format(File, "-module(~w).\n\n", [Modulename]),
|
io:format(File, "-module(~w).\n\n", [Modulename]),
|
||||||
io:format(File, "-include_lib(\"aebytecode/include/aeb_fate_data.hrl\").\n\n"
|
io:format(File, "-include_lib(\"gmbytecode/include/gmb_fate_data.hrl\").\n\n"
|
||||||
"-define(i(__X__), {immediate, __X__ }).\n\n"
|
"-define(i(__X__), {immediate, __X__ }).\n\n"
|
||||||
"-type fate_arg_immediate(T) :: {immediate, T}.\n"
|
"-type fate_arg_immediate(T) :: {immediate, T}.\n"
|
||||||
"-type fate_arg_var() :: {var, integer()}.\n"
|
"-type fate_arg_var() :: {var, integer()}.\n"
|
||||||
@ -324,7 +344,7 @@ generate_code_ops(Modulename, SrcDir, Ops) ->
|
|||||||
" | fate_arg_var()\n"
|
" | fate_arg_var()\n"
|
||||||
" | fate_arg_arg()\n"
|
" | fate_arg_arg()\n"
|
||||||
" | fate_arg_stack().\n\n"
|
" | fate_arg_stack().\n\n"
|
||||||
"-type fate_arg_immediate() :: {immediate, aeb_fate_data:fate_type()}.\n"
|
"-type fate_arg_immediate() :: {immediate, gmb_fate_data:fate_type()}.\n"
|
||||||
, []),
|
, []),
|
||||||
io:format(File, "~s", [Types]),
|
io:format(File, "~s", [Types]),
|
||||||
io:format(File, "-type fate_code() :: ~s\n~s .\n\n",
|
io:format(File, "-type fate_code() :: ~s\n~s .\n\n",
|
||||||
@ -369,15 +389,15 @@ gen_constructors(#{constructor := Function, format := ArgSpec,
|
|||||||
|
|
||||||
gen_arg_type_specs([]) -> [];
|
gen_arg_type_specs([]) -> [];
|
||||||
gen_arg_type_specs([a]) -> "fate_arg()";
|
gen_arg_type_specs([a]) -> "fate_arg()";
|
||||||
gen_arg_type_specs([is]) -> "aeb_fate_data:fate_string()";
|
gen_arg_type_specs([is]) -> "gmb_fate_data:fate_string()";
|
||||||
gen_arg_type_specs([ii]) -> "aeb_fate_data:fate_integer()";
|
gen_arg_type_specs([ii]) -> "gmb_fate_data:fate_integer()";
|
||||||
gen_arg_type_specs([li]) -> "[aeb_fate_data:fate_integer()]";
|
gen_arg_type_specs([li]) -> "[gmb_fate_data:fate_integer()]";
|
||||||
gen_arg_type_specs([t]) -> "aeb_fate_data:fate_type_type()";
|
gen_arg_type_specs([t]) -> "gmb_fate_data:fate_type_type()";
|
||||||
gen_arg_type_specs([a | Args]) -> "fate_arg(), " ++ gen_arg_type_specs(Args);
|
gen_arg_type_specs([a | Args]) -> "fate_arg(), " ++ gen_arg_type_specs(Args);
|
||||||
gen_arg_type_specs([is | Args]) -> "aeb_fate_data:fate_string(), " ++ gen_arg_type_specs(Args);
|
gen_arg_type_specs([is | Args]) -> "gmb_fate_data:fate_string(), " ++ gen_arg_type_specs(Args);
|
||||||
gen_arg_type_specs([ii | Args]) -> "aeb_fate_data:fate_integer(), " ++ gen_arg_type_specs(Args);
|
gen_arg_type_specs([ii | Args]) -> "gmb_fate_data:fate_integer(), " ++ gen_arg_type_specs(Args);
|
||||||
gen_arg_type_specs([li | Args]) -> "[aeb_fate_data:fate_integer()], " ++ gen_arg_type_specs(Args);
|
gen_arg_type_specs([li | Args]) -> "[gmb_fate_data:fate_integer()], " ++ gen_arg_type_specs(Args);
|
||||||
gen_arg_type_specs([t | Args]) -> "aeb_fate_data:fate_type_type(), " ++ gen_arg_type_specs(Args).
|
gen_arg_type_specs([t | Args]) -> "gmb_fate_data:fate_type_type(), " ++ gen_arg_type_specs(Args).
|
||||||
|
|
||||||
|
|
||||||
gen_arg_names(_, []) ->
|
gen_arg_names(_, []) ->
|
||||||
@ -409,7 +429,7 @@ ops_exports(Module, HrlFile, Exports) ->
|
|||||||
lists:flatten(io_lib:format(
|
lists:flatten(io_lib:format(
|
||||||
"-module(~w).\n\n"
|
"-module(~w).\n\n"
|
||||||
"-export([ ~s ]).\n\n"
|
"-export([ ~s ]).\n\n"
|
||||||
"-include_lib(\"aebytecode/" ++ HrlFile ++"\").\n\n"
|
"-include_lib(\"gmbytecode/" ++ HrlFile ++"\").\n\n"
|
||||||
"%%====================================================================\n"
|
"%%====================================================================\n"
|
||||||
"%% API\n"
|
"%% API\n"
|
||||||
"%%====================================================================\n",
|
"%%====================================================================\n",
|
||||||
@ -449,7 +469,7 @@ prelude(Doc) ->
|
|||||||
"%%%\n"
|
"%%%\n"
|
||||||
"%%% === === N O T E : This file is generated do not edit. === ===\n"
|
"%%% === === N O T E : This file is generated do not edit. === ===\n"
|
||||||
"%%%\n"
|
"%%%\n"
|
||||||
"%%% Source is in aeb_fate_generate_ops.erl\n"
|
"%%% Source is in gmb_fate_generate_ops.erl\n"
|
||||||
"%%% @doc\n"
|
"%%% @doc\n"
|
||||||
"%%% "++Doc++
|
"%%% "++Doc++
|
||||||
"%%% @end\n"
|
"%%% @end\n"
|
||||||
@ -498,10 +518,10 @@ expand_types([T]) -> expand_type(T);
|
|||||||
expand_types([T|Ts]) ->expand_type(T) ++ ", " ++ expand_types(Ts).
|
expand_types([T|Ts]) ->expand_type(T) ++ ", " ++ expand_types(Ts).
|
||||||
|
|
||||||
expand_type(a) -> "fate_arg()";
|
expand_type(a) -> "fate_arg()";
|
||||||
expand_type(is) -> "fate_arg_immediate(aeb_fate_data:fate_string())";
|
expand_type(is) -> "fate_arg_immediate(gmb_fate_data:fate_string())";
|
||||||
expand_type(ii) -> "fate_arg_immediate(aeb_fate_data:fate_integer())";
|
expand_type(ii) -> "fate_arg_immediate(gmb_fate_data:fate_integer())";
|
||||||
expand_type(li) -> "fate_arg_immediate([aeb_fate_data:fate_integer()])";
|
expand_type(li) -> "fate_arg_immediate([gmb_fate_data:fate_integer()])";
|
||||||
expand_type(t) -> "aeb_fate_data:fate_type_type()".
|
expand_type(t) -> "gmb_fate_data:fate_type_type()".
|
||||||
|
|
||||||
generate_scanner(TemplateFile, Outfile, Path, Ops) ->
|
generate_scanner(TemplateFile, Outfile, Path, Ops) ->
|
||||||
{ok, Template} = file:read_file(filename:join(Path,TemplateFile)),
|
{ok, Template} = file:read_file(filename:join(Path,TemplateFile)),
|
||||||
@ -521,8 +541,8 @@ insert_tokens_in_template(<<"%%% ###REPLACEWITHNOTE###", Rest/binary >>, Tokens)
|
|||||||
"%%%\n"
|
"%%%\n"
|
||||||
"%%% === === N O T E : This file is generated do not edit. === ===\n"
|
"%%% === === N O T E : This file is generated do not edit. === ===\n"
|
||||||
"%%%\n"
|
"%%%\n"
|
||||||
"%%% Source is in aeb_fate_generate_ops.erl\n"
|
"%%% Source is in gmb_fate_generate_ops.erl\n"
|
||||||
"%%% and aeb_fate_asm_scan.template"
|
"%%% and gmb_fate_asm_scan.template"
|
||||||
| insert_tokens_in_template(Rest, Tokens)];
|
| insert_tokens_in_template(Rest, Tokens)];
|
||||||
insert_tokens_in_template(<<B,Rest/binary>>, Tokens) ->
|
insert_tokens_in_template(<<B,Rest/binary>>, Tokens) ->
|
||||||
[B|insert_tokens_in_template(Rest, Tokens)].
|
[B|insert_tokens_in_template(Rest, Tokens)].
|
||||||
@ -538,9 +558,9 @@ gen_asm_pp(Module, Path, Ops) ->
|
|||||||
io:format(File,
|
io:format(File,
|
||||||
"-export([format_op/2]).\n\n"
|
"-export([format_op/2]).\n\n"
|
||||||
"format_arg(li, {immediate, LI}) ->\n"
|
"format_arg(li, {immediate, LI}) ->\n"
|
||||||
" aeb_fate_data:format(LI);\n"
|
" gmb_fate_data:format(LI);\n"
|
||||||
"format_arg(_, {immediate, I}) ->\n"
|
"format_arg(_, {immediate, I}) ->\n"
|
||||||
" aeb_fate_data:format(I);\n"
|
" gmb_fate_data:format(I);\n"
|
||||||
"format_arg(a, {arg, N}) -> io_lib:format(\"arg~~p\", [N]);\n"
|
"format_arg(a, {arg, N}) -> io_lib:format(\"arg~~p\", [N]);\n"
|
||||||
"format_arg(a, {var, N}) when N < 0 -> io_lib:format(\"store~~p\", [-N]);\n"
|
"format_arg(a, {var, N}) when N < 0 -> io_lib:format(\"store~~p\", [-N]);\n"
|
||||||
"format_arg(a, {var, N}) -> io_lib:format(\"var~~p\", [N]);\n"
|
"format_arg(a, {var, N}) -> io_lib:format(\"var~~p\", [N]);\n"
|
||||||
@ -778,50 +798,3 @@ gen_variant() ->
|
|||||||
3 -> "(| 2 | 0 | ( " ++ imm_arg() ++ ", " ++ imm_arg() ++ " ) |)"
|
3 -> "(| 2 | 0 | ( " ++ imm_arg() ++ ", " ++ imm_arg() ++ " ) |)"
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
%% TODO: add gas cost and end_bb/in_auth?
|
|
||||||
generate_documentation(Filename) ->
|
|
||||||
{ok, File} = file:open(Filename, [write]),
|
|
||||||
Instructions = lists:flatten([gen_doc(Op)++"\n" || Op <- get_ops()]),
|
|
||||||
io:format(File,
|
|
||||||
"### Operations\n\n"
|
|
||||||
"| OpCode | Name | Args | Description |\n"
|
|
||||||
"| --- | --- | --- | --- |\n"
|
|
||||||
"~s"
|
|
||||||
, [Instructions]),
|
|
||||||
io:format(File, "\n", []),
|
|
||||||
file:close(File).
|
|
||||||
|
|
||||||
gen_doc(#{ opname := Name
|
|
||||||
, opcode := OpCode
|
|
||||||
, arity := _Arity
|
|
||||||
, end_bb := _EndBB
|
|
||||||
, format := FateFormat
|
|
||||||
, macro := _Macro
|
|
||||||
, type_name := _TypeName
|
|
||||||
, doc := Doc
|
|
||||||
, gas := _Gas
|
|
||||||
, type := _Type
|
|
||||||
, constructor := _Constructor
|
|
||||||
, constructor_type := _ConstructorType
|
|
||||||
}) ->
|
|
||||||
Arguments =
|
|
||||||
case FateFormat of
|
|
||||||
[] -> "";
|
|
||||||
_ -> lists:join(" ",
|
|
||||||
[format_arg_doc(A) ||
|
|
||||||
A <-
|
|
||||||
lists:zip(FateFormat,
|
|
||||||
lists:seq(0,length(FateFormat)-1))])
|
|
||||||
end,
|
|
||||||
io_lib:format("| 0x~.16b | ~w | ~s | ~s |\n",
|
|
||||||
[ OpCode
|
|
||||||
, Name
|
|
||||||
, Arguments
|
|
||||||
, Doc]).
|
|
||||||
|
|
||||||
format_arg_doc({a, N}) -> io_lib:format("Arg~w", [N]);
|
|
||||||
format_arg_doc({is,_N}) -> "Identifier";
|
|
||||||
format_arg_doc({ii,_N}) -> "Integer";
|
|
||||||
format_arg_doc({li,_N}) -> "[Integers]";
|
|
||||||
format_arg_doc({t,_N}) -> "Type".
|
|
@ -1,4 +1,5 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Functions for manipulating FATE maps. In particular for mediating
|
%%% Functions for manipulating FATE maps. In particular for mediating
|
||||||
@ -6,9 +7,10 @@
|
|||||||
%%% fully or partially saved in the contract store.
|
%%% fully or partially saved in the contract store.
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% -------------------------------------------------------------------
|
%%% -------------------------------------------------------------------
|
||||||
-module(aeb_fate_maps).
|
-module(gmb_fate_maps).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-include("aeb_fate_data.hrl").
|
-include("gmb_fate_data.hrl").
|
||||||
|
|
||||||
-export([ allocate_store_maps/2
|
-export([ allocate_store_maps/2
|
||||||
, has_store_maps/1
|
, has_store_maps/1
|
||||||
@ -31,11 +33,11 @@
|
|||||||
-define(STORE_MAP_THRESHOLD, 100).
|
-define(STORE_MAP_THRESHOLD, 100).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-type fate_value() :: aeb_fate_data:fate_type().
|
-type fate_value() :: gmb_fate_data:fate_type().
|
||||||
-type fate_value_or_tombstone() :: fate_value() | ?FATE_MAP_TOMBSTONE.
|
-type fate_value_or_tombstone() :: fate_value() | ?FATE_MAP_TOMBSTONE.
|
||||||
-type id() :: integer().
|
-type id() :: integer().
|
||||||
-type used_ids() :: list(id()).
|
-type used_ids() :: list(id()).
|
||||||
-type maps() :: #{ id() => aeb_fate_data:fate_map() | aeb_fate_data:fate_store_map() }.
|
-type maps() :: #{ id() => gmb_fate_data:fate_map() | gmb_fate_data:fate_store_map() }.
|
||||||
|
|
||||||
%% -- Allocating store maps --------------------------------------------------
|
%% -- Allocating store maps --------------------------------------------------
|
||||||
|
|
||||||
@ -70,7 +72,7 @@ allocate_store_maps(Used, ?FATE_VARIANT(Arities, Tag, Vals), Maps) ->
|
|||||||
allocate_store_maps(Used, Val, Maps) when ?IS_FATE_MAP(Val) ->
|
allocate_store_maps(Used, Val, Maps) when ?IS_FATE_MAP(Val) ->
|
||||||
{Used1, KVs, Maps1} = allocate_store_maps_m(Used, ?FATE_MAP_VALUE(Val), Maps),
|
{Used1, KVs, Maps1} = allocate_store_maps_m(Used, ?FATE_MAP_VALUE(Val), Maps),
|
||||||
Val1 = ?MAKE_FATE_MAP(KVs),
|
Val1 = ?MAKE_FATE_MAP(KVs),
|
||||||
case byte_size(aeb_fate_encoding:serialize(Val1)) < ?STORE_MAP_THRESHOLD of
|
case byte_size(gmb_fate_encoding:serialize(Val1)) < ?STORE_MAP_THRESHOLD of
|
||||||
true -> {Used1, Val1, Maps1};
|
true -> {Used1, Val1, Maps1};
|
||||||
false ->
|
false ->
|
||||||
{Id, Used2} = next_id(Used1),
|
{Id, Used2} = next_id(Used1),
|
||||||
@ -97,7 +99,7 @@ allocate_store_maps_m(Used, Val, Maps) ->
|
|||||||
|
|
||||||
%% -- Unfolding store maps ---------------------------------------------------
|
%% -- Unfolding store maps ---------------------------------------------------
|
||||||
|
|
||||||
-type unfold_fun() :: fun((id()) -> aeb_fate_data:fate_map()).
|
-type unfold_fun() :: fun((id()) -> gmb_fate_data:fate_map()).
|
||||||
|
|
||||||
-spec unfold_store_maps(unfold_fun(), fate_value_or_tombstone()) -> fate_value_or_tombstone().
|
-spec unfold_store_maps(unfold_fun(), fate_value_or_tombstone()) -> fate_value_or_tombstone().
|
||||||
unfold_store_maps(_Unfold, ?FATE_MAP_TOMBSTONE = Val) -> Val;
|
unfold_store_maps(_Unfold, ?FATE_MAP_TOMBSTONE = Val) -> Val;
|
@ -1,4 +1,5 @@
|
|||||||
-module(aeb_heap).
|
-module(gmb_heap).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ to_binary/1
|
-export([ to_binary/1
|
||||||
, to_binary/2
|
, to_binary/2
|
||||||
@ -22,8 +23,8 @@
|
|||||||
|
|
||||||
-export_type([binary_value/0, heap_value/0, offset/0, heap_fragment/0]).
|
-export_type([binary_value/0, heap_value/0, offset/0, heap_fragment/0]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_typerep_def.hrl").
|
-include_lib("gmbytecode/include/gmb_typerep_def.hrl").
|
||||||
-include_lib("aebytecode/include/aeb_heap.hrl").
|
-include_lib("gmbytecode/include/gmb_heap.hrl").
|
||||||
|
|
||||||
-type word() :: non_neg_integer().
|
-type word() :: non_neg_integer().
|
||||||
-type pointer() :: word().
|
-type pointer() :: word().
|
||||||
@ -112,7 +113,7 @@ pmap_size(#pmap{data = Data}) when is_map(Data) ->
|
|||||||
|
|
||||||
%% -- Value to binary --------------------------------------------------------
|
%% -- Value to binary --------------------------------------------------------
|
||||||
|
|
||||||
-spec to_binary(aeb_aevm_data:data()) -> aeb_aevm_data:heap().
|
-spec to_binary(gmb_aevm_data:data()) -> gmb_aevm_data:heap().
|
||||||
%% Encode the data as a heap where the first word is the value (for unboxed
|
%% Encode the data as a heap where the first word is the value (for unboxed
|
||||||
%% types) or a pointer to the value (for boxed types).
|
%% types) or a pointer to the value (for boxed types).
|
||||||
to_binary(Data) ->
|
to_binary(Data) ->
|
||||||
@ -131,10 +132,10 @@ to_binary1(Data,_Address) when is_integer(Data) ->
|
|||||||
{Data,<<>>};
|
{Data,<<>>};
|
||||||
to_binary1(Data, Address) when is_binary(Data) ->
|
to_binary1(Data, Address) when is_binary(Data) ->
|
||||||
%% a string
|
%% a string
|
||||||
Words = aeb_memory:binary_to_words(Data),
|
Words = gmb_memory:binary_to_words(Data),
|
||||||
{Address,<<(size(Data)):256, << <<W:256>> || W <- Words>>/binary>>};
|
{Address,<<(size(Data)):256, << <<W:256>> || W <- Words>>/binary>>};
|
||||||
to_binary1({contract_bytearray, FateCode}, Address) when is_binary(FateCode) ->
|
to_binary1({contract_bytearray, FateCode}, Address) when is_binary(FateCode) ->
|
||||||
Words = aeb_memory:binary_to_words(FateCode),
|
Words = gmb_memory:binary_to_words(FateCode),
|
||||||
{Address,<<(size(FateCode)):256, << <<W:256>> || W <- Words>>/binary>>};
|
{Address,<<(size(FateCode)):256, << <<W:256>> || W <- Words>>/binary>>};
|
||||||
to_binary1(none, Address) -> to_binary1({variant, 0, []}, Address);
|
to_binary1(none, Address) -> to_binary1({variant, 0, []}, Address);
|
||||||
to_binary1({some, Value}, Address) -> to_binary1({variant, 1, [Value]}, Address);
|
to_binary1({some, Value}, Address) -> to_binary1({variant, 1, [Value]}, Address);
|
@ -1,12 +1,15 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Memory speifics that compiler and VM need to agree upon
|
%%% Memory speifics that compiler and VM need to agree upon
|
||||||
%%% @end
|
%%% @end
|
||||||
|
%%% Updated : 22 Jan 2025
|
||||||
%%% Created : 19 Dec 2018
|
%%% Created : 19 Dec 2018
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_memory).
|
-module(gmb_memory).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([binary_to_words/1]).
|
-export([binary_to_words/1]).
|
||||||
|
|
@ -1,12 +1,15 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Opcodes
|
%%% Opcodes
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% Created : 2 Oct 2017
|
%%% Updated : 22 Jan 2025
|
||||||
|
%%% Created : 02 Oct 2017
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_opcodes).
|
-module(gmb_opcodes).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([ dup/1
|
-export([ dup/1
|
||||||
, mnemonic/1
|
, mnemonic/1
|
||||||
@ -17,7 +20,7 @@
|
|||||||
, swap/1
|
, swap/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
@ -1,18 +1,21 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||||
%%% @doc
|
%%% @doc
|
||||||
%%% Handle interaction with the aeternity chain
|
%%% Handle interaction with the gmternity chain
|
||||||
%%% through calls to AEternity primitive operations at address 0.
|
%%% through calls to AEternity primitive operations at address 0.
|
||||||
%%% @end
|
%%% @end
|
||||||
|
%%% Updated : 22 Jan 2025
|
||||||
%%% Created : 18 Dec 2018
|
%%% Created : 18 Dec 2018
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_primops).
|
-module(gmb_primops).
|
||||||
|
-vsn("3.4.1").
|
||||||
-export([ is_local_primop_op/1
|
-export([ is_local_primop_op/1
|
||||||
, op_needs_type_check/1
|
, op_needs_type_check/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("aeb_opcodes.hrl").
|
-include("gmb_opcodes.hrl").
|
||||||
|
|
||||||
is_local_primop_op(Op) when ?PRIM_CALL_IN_MAP_RANGE(Op) -> true;
|
is_local_primop_op(Op) when ?PRIM_CALL_IN_MAP_RANGE(Op) -> true;
|
||||||
is_local_primop_op(Op) when ?PRIM_CALL_IN_CRYPTO_RANGE(Op) -> true;
|
is_local_primop_op(Op) when ?PRIM_CALL_IN_CRYPTO_RANGE(Op) -> true;
|
@ -1,12 +1,12 @@
|
|||||||
{application, aebytecode,
|
{application, gmbytecode,
|
||||||
[{description, "Bytecode definitions, serialization and deserialization for aeternity."},
|
[{description, "Bytecode definitions, serialization and deserialization for the Gajumaru."},
|
||||||
{vsn, "2.1.0"},
|
{vsn, "3.4.1"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[kernel,
|
[kernel,
|
||||||
stdlib,
|
stdlib,
|
||||||
eblake2,
|
eblake2,
|
||||||
aeserialization,
|
gmserialization,
|
||||||
getopt
|
getopt
|
||||||
]},
|
]},
|
||||||
{env,[]},
|
{env,[]},
|
@ -1,4 +1,5 @@
|
|||||||
-module(aefateasm).
|
-module(gmfateasm).
|
||||||
|
-vsn("3.4.1").
|
||||||
|
|
||||||
-export([main/1]).
|
-export([main/1]).
|
||||||
|
|
||||||
@ -9,7 +10,7 @@
|
|||||||
, {outfile, $o, "out", string, "Output file (experimental)"} ]).
|
, {outfile, $o, "out", string, "Output file (experimental)"} ]).
|
||||||
|
|
||||||
usage() ->
|
usage() ->
|
||||||
getopt:usage(?OPT_SPEC, "aefateasm").
|
getopt:usage(?OPT_SPEC, "gmfateasm").
|
||||||
|
|
||||||
main(Args) ->
|
main(Args) ->
|
||||||
case getopt:parse(?OPT_SPEC, Args) of
|
case getopt:parse(?OPT_SPEC, Args) of
|
||||||
@ -43,8 +44,8 @@ assemble(File, Opts) ->
|
|||||||
Verbose = proplists:get_value(verbose, Opts, false),
|
Verbose = proplists:get_value(verbose, Opts, false),
|
||||||
case proplists:get_value(outfile, Opts, undefined) of
|
case proplists:get_value(outfile, Opts, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
Asm = aeb_fate_asm:read_file(File),
|
Asm = gmb_fate_asm:read_file(File),
|
||||||
{Env, BC} = aeb_fate_asm:asm_to_bytecode(Asm, Opts),
|
{Env, BC} = gmb_fate_asm:asm_to_bytecode(Asm, Opts),
|
||||||
case Verbose of
|
case Verbose of
|
||||||
true ->
|
true ->
|
||||||
io:format("Env: ~0p~n", [Env]);
|
io:format("Env: ~0p~n", [Env]);
|
||||||
@ -52,6 +53,6 @@ assemble(File, Opts) ->
|
|||||||
end,
|
end,
|
||||||
io:format("Code: ~0p~n", [BC]);
|
io:format("Code: ~0p~n", [BC]);
|
||||||
OutFile ->
|
OutFile ->
|
||||||
aeb_fate_asm:assemble_file(File, OutFile, Opts)
|
gmb_fate_asm:assemble_file(File, OutFile, Opts)
|
||||||
end.
|
end.
|
||||||
|
|
@ -1,97 +0,0 @@
|
|||||||
%%%-------------------------------------------------------------------
|
|
||||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
|
||||||
%%% @doc Basic tests for Fate serialization
|
|
||||||
%%%
|
|
||||||
%%% To run:
|
|
||||||
%%% TEST=aeb_serialize_test rebar3 eunit
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%%-------------------------------------------------------------------
|
|
||||||
|
|
||||||
-module(aeb_serialize_test).
|
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
|
|
||||||
serialize_integer_test() ->
|
|
||||||
<<0>> = aeb_fate_encoding:serialize(aeb_fate_data:make_integer(0)),
|
|
||||||
<<2>> = aeb_fate_encoding:serialize(aeb_fate_data:make_integer(1)),
|
|
||||||
<<126>> = aeb_fate_encoding:serialize(aeb_fate_data:make_integer(63)),
|
|
||||||
<<111, 0>> = aeb_fate_encoding:serialize(aeb_fate_data:make_integer(64)),
|
|
||||||
<<111,130,255,255>> = aeb_fate_encoding:serialize(aeb_fate_data:make_integer(65535 + 64)),
|
|
||||||
<<111,184,129,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>> =
|
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_integer(1 bsl 1024 + 64)).
|
|
||||||
|
|
||||||
serialize_deserialize_test_() ->
|
|
||||||
[{lists:flatten(io_lib:format("~p", [X])),
|
|
||||||
fun() ->
|
|
||||||
?assertEqual(X,
|
|
||||||
aeb_fate_encoding:deserialize(aeb_fate_encoding:serialize(X)))
|
|
||||||
end}
|
|
||||||
|| X <- sources()].
|
|
||||||
|
|
||||||
make_int_list(N) -> [aeb_fate_data:make_integer(I) || I <- lists:seq(1, N)].
|
|
||||||
|
|
||||||
sources() ->
|
|
||||||
FortyTwo = aeb_fate_data:make_integer(42),
|
|
||||||
Unit = aeb_fate_data:make_unit(),
|
|
||||||
True = aeb_fate_data:make_boolean(true),
|
|
||||||
False = aeb_fate_data:make_boolean(false),
|
|
||||||
Nil = aeb_fate_data:make_list([]),
|
|
||||||
EmptyString = aeb_fate_data:make_string(""),
|
|
||||||
EmptyMap = aeb_fate_data:make_map(#{}),
|
|
||||||
[aeb_fate_data:make_integer(0),
|
|
||||||
aeb_fate_data:make_integer(1),
|
|
||||||
True, False, Unit, Nil, EmptyString, EmptyMap,
|
|
||||||
aeb_fate_data:make_hash(<<1,2,3,4,5>>),
|
|
||||||
aeb_fate_data:make_signature(<<1,2,3,4,5>>),
|
|
||||||
aeb_fate_data:make_contract(<<1,2,3,4,5>>),
|
|
||||||
aeb_fate_data:make_channel(<<1,2,3,4,5>>),
|
|
||||||
aeb_fate_data:make_list([True]),
|
|
||||||
aeb_fate_data:make_address(
|
|
||||||
<<0,1,2,3,4,5,6,7,8,9,
|
|
||||||
0,1,2,3,4,5,6,7,8,9,
|
|
||||||
0,1,2,3,4,5,6,7,8,9,
|
|
||||||
1,2>>),
|
|
||||||
aeb_fate_data:make_string(<<"Hello">>),
|
|
||||||
aeb_fate_data:make_string(
|
|
||||||
<<"0123456789012345678901234567890123456789"
|
|
||||||
"0123456789012345678901234567890123456789"
|
|
||||||
"0123456789012345678901234567890123456789"
|
|
||||||
"0123456789012345678901234567890123456789">>), %% Magic concat 80 char string.
|
|
||||||
aeb_fate_data:make_tuple({True, FortyTwo}),
|
|
||||||
aeb_fate_data:make_tuple(list_to_tuple(make_int_list(65))),
|
|
||||||
aeb_fate_data:make_tuple(list_to_tuple(make_int_list(16))),
|
|
||||||
aeb_fate_data:make_map(#{ aeb_fate_data:make_integer(1) => True, aeb_fate_data:make_integer(2) => False}),
|
|
||||||
aeb_fate_data:make_map(#{ aeb_fate_data:make_string(<<"foo">>) => aeb_fate_data:make_tuple({FortyTwo, True})}),
|
|
||||||
aeb_fate_data:make_list(make_int_list(3)),
|
|
||||||
aeb_fate_data:make_integer(-65),
|
|
||||||
aeb_fate_data:make_integer(65),
|
|
||||||
aeb_fate_data:make_integer(-32432847932847928374983),
|
|
||||||
aeb_fate_data:make_bits(0),
|
|
||||||
aeb_fate_data:make_bits(1),
|
|
||||||
aeb_fate_data:make_bits(-1),
|
|
||||||
aeb_fate_data:make_list(make_int_list(65)),
|
|
||||||
aeb_fate_data:make_variant([1,2,3], 0, {FortyTwo}),
|
|
||||||
aeb_fate_data:make_variant([2,0], 1, {}),
|
|
||||||
aeb_fate_data:make_list([aeb_fate_data:make_variant([0,0,0], 0, {})]),
|
|
||||||
aeb_fate_data:make_variant([0|| _<-lists:seq(1,255)], 254, {}),
|
|
||||||
aeb_fate_data:make_variant([0,1,2,3,4,5],
|
|
||||||
3, {aeb_fate_data:make_boolean(true),
|
|
||||||
aeb_fate_data:make_list(make_int_list(3)),
|
|
||||||
aeb_fate_data:make_string(<<"foo">>)}),
|
|
||||||
%% contract C =
|
|
||||||
%% type state = int
|
|
||||||
%% entrypoint init() = 2137
|
|
||||||
|
|
||||||
%% cb_+FFGA6Af6sHTrctrcNGwEa8MPei7iEHIjnxcsBzlA5IK0Yn11sCllP5E1kQfADcANwAaDoJvgggZAQM/jC8BEUTWRB8RaW5pdIIvAIU0LjMuMAD7u
|
|
||||||
aeb_fate_data:make_contract_bytearray(
|
|
||||||
<<248,81,70,3,160,31,234,193,211,173,203,107,112,209,176,17,175,12,61,232,187,
|
|
||||||
136,65,200,142,124,92,176,28,229,3,146,10,209,137,245,214,192,165,148,254,68,
|
|
||||||
214,68,31,0,55,0,55,0,26,14,130,111,130,8,25,1,3,63,140,47,1,17,68,214,68,31,
|
|
||||||
17,105,110,105,116,130,47,0,133,52,46,51,46,48,0>>)
|
|
||||||
].
|
|
@ -62,13 +62,13 @@ id_local: JUMPDEST
|
|||||||
JUMP
|
JUMP
|
||||||
|
|
||||||
;; Test the code from the shell
|
;; Test the code from the shell
|
||||||
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => list_to_binary(aeb_asm:file("apps/aesophia/test/contracts/identity.aesm", [])), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0 }, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{})).
|
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => list_to_binary(gmb_asm:file("apps/gmsophia/test/contracts/identity.aesm", [])), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0 }, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{})).
|
||||||
|
|
||||||
;; Test the code from the shell with tracing.
|
;; Test the code from the shell with tracing.
|
||||||
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => aeb_asm:file("apps/aesophia/test/contracts/identity.aesm", []), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0 }, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{ trace => true})).
|
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => gmb_asm:file("apps/gmsophia/test/contracts/identity.aesm", []), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0 }, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{ trace => true})).
|
||||||
|
|
||||||
|
|
||||||
;; Test the code from the shell with tracing.
|
;; Test the code from the shell with tracing.
|
||||||
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => aeb_asm:file("apps/aesophia/test/contracts/identity.aesm", [pp_tokens, pp_opcodes, pp_patched_code, pp_hex_string]), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0}, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{ trace => true})).
|
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => gmb_asm:file("apps/gmsophia/test/contracts/identity.aesm", [pp_tokens, pp_opcodes, pp_patched_code, pp_hex_string]), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0}, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{ trace => true})).
|
||||||
|
|
||||||
;; aec_conductor:stop_mining().
|
;; aec_conductor:stop_mining().
|
||||||
|
@ -5,4 +5,4 @@ FUNCTION id(integer) -> integer
|
|||||||
;; Test the code from the shell
|
;; Test the code from the shell
|
||||||
;; _build/default/rel/aessembler/bin/aessembler console
|
;; _build/default/rel/aessembler/bin/aessembler console
|
||||||
|
|
||||||
;; aeb_aefa:file("../../../../test/asm_code/identity.fate", []).
|
;; gmb_gmfa:file("../../../../test/asm_code/identity.fate", []).
|
||||||
|
@ -68,9 +68,6 @@ FUNCTION tuple() : {tuple, [integer, boolean, string, {tuple, [integer, integer]
|
|||||||
FUNCTION address() : address
|
FUNCTION address() : address
|
||||||
RETURNR @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
RETURNR @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
FUNCTION oracle() : oracle
|
|
||||||
RETURNR @ok_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
|
||||||
|
|
||||||
FUNCTION contract() : contract
|
FUNCTION contract() : contract
|
||||||
RETURNR @ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
RETURNR @ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
;; CONTRACT oracles
|
|
||||||
|
|
||||||
FUNCTION register (address, integer, {variant, [{tuple, [integer]}, {tuple, [integer]}]}) : oracle
|
|
||||||
ORACLE_REGISTER a #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== arg0 arg1 arg2 'string '{variant, [{tuple, []}, {tuple, [integer]}]}
|
|
||||||
RETURN
|
|
||||||
|
|
||||||
FUNCTION query (oracle, integer, string) : oracle_query
|
|
||||||
ORACLE_QUERY a arg0 arg1 arg2 (| [1,1] | 0 | (100) |) (| [1,1] | 0 | (100) |) 'string '{variant, [{tuple, []}, {tuple, [integer]}]}
|
|
||||||
RETURN
|
|
||||||
|
|
||||||
FUNCTION bogus_query () : oracle_query
|
|
||||||
RETURNR @oq_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
|
||||||
|
|
||||||
FUNCTION respond (oracle, integer, string) : {tuple, []}
|
|
||||||
ORACLE_RESPOND #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== arg0 arg1 arg2 'string '{variant, [{tuple, []}, {tuple, [integer]}]}
|
|
||||||
RETURNR {}
|
|
||||||
|
|
||||||
FUNCTION extend (oracle, {variant, [{tuple, [integer]}, {tuple, [integer]}]}) : {tuple, []}
|
|
||||||
ORACLE_EXTEND #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== arg0 arg1
|
|
||||||
RETURNR {}
|
|
||||||
|
|
||||||
FUNCTION get_question (oracle, oracle_query) : string
|
|
||||||
ORACLE_GET_QUESTION a arg0 arg1 'string '{variant, [{tuple, []}, {tuple, [integer]}]}
|
|
||||||
RETURN
|
|
||||||
|
|
||||||
FUNCTION get_answer (oracle, oracle_query) : {variant, [{tuple, []}, {tuple, [string]}]}
|
|
||||||
ORACLE_GET_ANSWER a arg1 arg2 'string '{variant, [{tuple, []}, {tuple, [integer]}]}
|
|
||||||
RETURN
|
|
||||||
|
|
||||||
FUNCTION query_fee (oracle) : integer
|
|
||||||
ORACLE_QUERY_FEE a arg0
|
|
||||||
RETURN
|
|
@ -37,5 +37,5 @@ FUNCTION tailcall(integer) -> integer
|
|||||||
;; Test the code from the shell
|
;; Test the code from the shell
|
||||||
;; _build/default/rel/aessembler/bin/aessembler console
|
;; _build/default/rel/aessembler/bin/aessembler console
|
||||||
|
|
||||||
;; aeb_aefa:file("../../../../test/asm_code/test.fate", []).
|
;; gmb_gmfa:file("../../../../test/asm_code/test.fate", []).
|
||||||
;; f(Asm), f(Env), f(BC), Asm = aefa_asm:read_file("../../../../test/asm_code/test.fate"), {Env, BC} = aefa_asm:asm_to_bytecode(Asm, []), aefa_asm:bytecode_to_fate_code(BC, []).
|
;; f(Asm), f(Env), f(BC), Asm = gmfa_asm:read_file("../../../../test/asm_code/test.fate"), {Env, BC} = gmfa_asm:asm_to_bytecode(Asm, []), gmfa_asm:bytecode_to_fate_code(BC, []).
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||||
%%% @doc Basic tests for Fate data
|
%%% @doc Basic tests for Fate data
|
||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_data_test).
|
-module(gmb_data_test).
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
format_integer_test() ->
|
format_integer_test() ->
|
||||||
"0" = aeb_fate_data:format(0).
|
"0" = gmb_fate_data:format(0).
|
@ -1,19 +1,20 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
%%% @copyright (C) 2018, Aeternity Anstalt
|
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||||
%%% @doc Basic tests for Fate serialization
|
%%% @doc Basic tests for Fate serialization
|
||||||
%%%
|
%%%
|
||||||
%%% To run:
|
%%% To run:
|
||||||
%%% TEST=aeb_fate_asm_test rebar3 eunit
|
%%% TEST=gmb_fate_asm_test rebar3 eunit
|
||||||
%%%
|
%%%
|
||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_fate_asm_test).
|
-module(gmb_fate_asm_test).
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
asm_path() ->
|
asm_path() ->
|
||||||
filename:join(code:lib_dir(aebytecode, test), "asm_code").
|
filename:join(code:lib_dir(gmbytecode, test), "asm_code").
|
||||||
|
|
||||||
|
|
||||||
file_path(File) ->
|
file_path(File) ->
|
||||||
@ -21,11 +22,11 @@ file_path(File) ->
|
|||||||
|
|
||||||
read_file(File) ->
|
read_file(File) ->
|
||||||
FilePath = file_path(File),
|
FilePath = file_path(File),
|
||||||
Asm = aeb_fate_asm:read_file(FilePath),
|
Asm = gmb_fate_asm:read_file(FilePath),
|
||||||
Asm.
|
Asm.
|
||||||
|
|
||||||
assemble(Asm) ->
|
assemble(Asm) ->
|
||||||
aeb_fate_asm:asm_to_bytecode(Asm, []).
|
gmb_fate_asm:asm_to_bytecode(Asm, []).
|
||||||
|
|
||||||
asm_disasm_idenity_test() ->
|
asm_disasm_idenity_test() ->
|
||||||
check_roundtrip(identity).
|
check_roundtrip(identity).
|
||||||
@ -48,19 +49,18 @@ sources() ->
|
|||||||
, "mapofmap"
|
, "mapofmap"
|
||||||
, "immediates"
|
, "immediates"
|
||||||
, "names"
|
, "names"
|
||||||
, "oracles"
|
|
||||||
, "meta"
|
, "meta"
|
||||||
].
|
].
|
||||||
|
|
||||||
check_roundtrip(File) ->
|
check_roundtrip(File) ->
|
||||||
AssemblerCode = read_file(File),
|
AssemblerCode = read_file(File),
|
||||||
{_Env, ByteCode} = assemble(AssemblerCode),
|
{_Env, ByteCode} = assemble(AssemblerCode),
|
||||||
FateCode = aeb_fate_code:deserialize(ByteCode),
|
FateCode = gmb_fate_code:deserialize(ByteCode),
|
||||||
DissasmCode = aeb_fate_asm:to_asm(FateCode),
|
DissasmCode = gmb_fate_asm:to_asm(FateCode),
|
||||||
{_Env2, ByteCode2} = assemble(DissasmCode),
|
{_Env2, ByteCode2} = assemble(DissasmCode),
|
||||||
ByteCode3 = aeb_fate_code:serialize(FateCode),
|
ByteCode3 = gmb_fate_code:serialize(FateCode),
|
||||||
Code1 = aeb_fate_asm:strip(ByteCode),
|
Code1 = gmb_fate_asm:strip(ByteCode),
|
||||||
Code2 = aeb_fate_asm:strip(ByteCode2),
|
Code2 = gmb_fate_asm:strip(ByteCode2),
|
||||||
Code3 = aeb_fate_asm:strip(ByteCode3),
|
Code3 = gmb_fate_asm:strip(ByteCode3),
|
||||||
?assertEqual(Code1, Code2),
|
?assertEqual(Code1, Code2),
|
||||||
?assertEqual(Code1, Code3).
|
?assertEqual(Code1, Code3).
|
98
test/gmb_serialize_test.erl
Normal file
98
test/gmb_serialize_test.erl
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2025, QPQ AG
|
||||||
|
%%% @copyright (C) 2018, Aeternity Anstalt
|
||||||
|
%%% @doc Basic tests for Fate serialization
|
||||||
|
%%%
|
||||||
|
%%% To run:
|
||||||
|
%%% TEST=gmb_serialize_test rebar3 eunit
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(gmb_serialize_test).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
serialize_integer_test() ->
|
||||||
|
<<0>> = gmb_fate_encoding:serialize(gmb_fate_data:make_integer(0)),
|
||||||
|
<<2>> = gmb_fate_encoding:serialize(gmb_fate_data:make_integer(1)),
|
||||||
|
<<126>> = gmb_fate_encoding:serialize(gmb_fate_data:make_integer(63)),
|
||||||
|
<<111, 0>> = gmb_fate_encoding:serialize(gmb_fate_data:make_integer(64)),
|
||||||
|
<<111,130,255,255>> = gmb_fate_encoding:serialize(gmb_fate_data:make_integer(65535 + 64)),
|
||||||
|
<<111,184,129,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>> =
|
||||||
|
gmb_fate_encoding:serialize(gmb_fate_data:make_integer(1 bsl 1024 + 64)).
|
||||||
|
|
||||||
|
serialize_deserialize_test_() ->
|
||||||
|
[{lists:flatten(io_lib:format("~p", [X])),
|
||||||
|
fun() ->
|
||||||
|
?assertEqual(X,
|
||||||
|
gmb_fate_encoding:deserialize(gmb_fate_encoding:serialize(X)))
|
||||||
|
end}
|
||||||
|
|| X <- sources()].
|
||||||
|
|
||||||
|
make_int_list(N) -> [gmb_fate_data:make_integer(I) || I <- lists:seq(1, N)].
|
||||||
|
|
||||||
|
sources() ->
|
||||||
|
FortyTwo = gmb_fate_data:make_integer(42),
|
||||||
|
Unit = gmb_fate_data:make_unit(),
|
||||||
|
True = gmb_fate_data:make_boolean(true),
|
||||||
|
False = gmb_fate_data:make_boolean(false),
|
||||||
|
Nil = gmb_fate_data:make_list([]),
|
||||||
|
EmptyString = gmb_fate_data:make_string(""),
|
||||||
|
EmptyMap = gmb_fate_data:make_map(#{}),
|
||||||
|
[gmb_fate_data:make_integer(0),
|
||||||
|
gmb_fate_data:make_integer(1),
|
||||||
|
True, False, Unit, Nil, EmptyString, EmptyMap,
|
||||||
|
gmb_fate_data:make_hash(<<1,2,3,4,5>>),
|
||||||
|
gmb_fate_data:make_signature(<<1,2,3,4,5>>),
|
||||||
|
gmb_fate_data:make_contract(<<1,2,3,4,5>>),
|
||||||
|
gmb_fate_data:make_channel(<<1,2,3,4,5>>),
|
||||||
|
gmb_fate_data:make_list([True]),
|
||||||
|
gmb_fate_data:make_address(
|
||||||
|
<<0,1,2,3,4,5,6,7,8,9,
|
||||||
|
0,1,2,3,4,5,6,7,8,9,
|
||||||
|
0,1,2,3,4,5,6,7,8,9,
|
||||||
|
1,2>>),
|
||||||
|
gmb_fate_data:make_string(<<"Hello">>),
|
||||||
|
gmb_fate_data:make_string(
|
||||||
|
<<"0123456789012345678901234567890123456789"
|
||||||
|
"0123456789012345678901234567890123456789"
|
||||||
|
"0123456789012345678901234567890123456789"
|
||||||
|
"0123456789012345678901234567890123456789">>), %% Magic concat 80 char string.
|
||||||
|
gmb_fate_data:make_tuple({True, FortyTwo}),
|
||||||
|
gmb_fate_data:make_tuple(list_to_tuple(make_int_list(65))),
|
||||||
|
gmb_fate_data:make_tuple(list_to_tuple(make_int_list(16))),
|
||||||
|
gmb_fate_data:make_map(#{ gmb_fate_data:make_integer(1) => True, gmb_fate_data:make_integer(2) => False}),
|
||||||
|
gmb_fate_data:make_map(#{ gmb_fate_data:make_string(<<"foo">>) => gmb_fate_data:make_tuple({FortyTwo, True})}),
|
||||||
|
gmb_fate_data:make_list(make_int_list(3)),
|
||||||
|
gmb_fate_data:make_integer(-65),
|
||||||
|
gmb_fate_data:make_integer(65),
|
||||||
|
gmb_fate_data:make_integer(-32432847932847928374983),
|
||||||
|
gmb_fate_data:make_bits(0),
|
||||||
|
gmb_fate_data:make_bits(1),
|
||||||
|
gmb_fate_data:make_bits(-1),
|
||||||
|
gmb_fate_data:make_list(make_int_list(65)),
|
||||||
|
gmb_fate_data:make_variant([1,2,3], 0, {FortyTwo}),
|
||||||
|
gmb_fate_data:make_variant([2,0], 1, {}),
|
||||||
|
gmb_fate_data:make_list([gmb_fate_data:make_variant([0,0,0], 0, {})]),
|
||||||
|
gmb_fate_data:make_variant([0|| _<-lists:seq(1,255)], 254, {}),
|
||||||
|
gmb_fate_data:make_variant([0,1,2,3,4,5],
|
||||||
|
3, {gmb_fate_data:make_boolean(true),
|
||||||
|
gmb_fate_data:make_list(make_int_list(3)),
|
||||||
|
gmb_fate_data:make_string(<<"foo">>)}),
|
||||||
|
%% contract C =
|
||||||
|
%% type state = int
|
||||||
|
%% entrypoint init() = 2137
|
||||||
|
|
||||||
|
%% cb_+FFGA6Af6sHTrctrcNGwEa8MPei7iEHIjnxcsBzlA5IK0Yn11sCllP5E1kQfADcANwAaDoJvgggZAQM/jC8BEUTWRB8RaW5pdIIvAIU0LjMuMAD7u
|
||||||
|
gmb_fate_data:make_contract_bytearray(
|
||||||
|
<<248,81,70,3,160,31,234,193,211,173,203,107,112,209,176,17,175,12,61,232,187,
|
||||||
|
136,65,200,142,124,92,176,28,229,3,146,10,209,137,245,214,192,165,148,254,68,
|
||||||
|
214,68,31,0,55,0,55,0,26,14,130,111,130,8,25,1,3,63,140,47,1,17,68,214,68,31,
|
||||||
|
17,105,110,105,116,130,47,0,133,52,46,51,46,48,0>>)
|
||||||
|
].
|
@ -1,4 +1,4 @@
|
|||||||
-module(aebytecode_SUITE).
|
-module(gmbytecode_SUITE).
|
||||||
|
|
||||||
%% common_test exports
|
%% common_test exports
|
||||||
-export([ all/0 ]).
|
-export([ all/0 ]).
|
||||||
@ -12,8 +12,8 @@ all() ->
|
|||||||
[ roundtrip_identy ].
|
[ roundtrip_identy ].
|
||||||
|
|
||||||
roundtrip_identy(_Cfg) ->
|
roundtrip_identy(_Cfg) ->
|
||||||
CodeDir = code:lib_dir(aebytecode, test),
|
CodeDir = code:lib_dir(gmbytecode, test),
|
||||||
FileName = filename:join(CodeDir, "asm_code/identity.aesm"),
|
FileName = filename:join(CodeDir, "asm_code/identity.gmsm"),
|
||||||
Code = aeb_asm:file(FileName, []),
|
Code = gmb_asm:file(FileName, []),
|
||||||
ct:log("Code ~p:~n~s~n", [FileName, aeb_disassemble:format(Code, fun io:format/2)]),
|
ct:log("Code ~p:~n~s~n", [FileName, gmb_disassemble:format(Code, fun io:format/2)]),
|
||||||
ok.
|
ok.
|
19
zomp.meta
Normal file
19
zomp.meta
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{name,"Gajumaru Bytecode"}.
|
||||||
|
{type,lib}.
|
||||||
|
{modules,[]}.
|
||||||
|
{prefix,none}.
|
||||||
|
{desc,"A library and stand alone assembler for Gajumaru bytecode. This version supports AEVM bytecode and FATE bytecode."}.
|
||||||
|
{author,[]}.
|
||||||
|
{package_id,{"otpr","gmbytecode",{3,4,1}}}.
|
||||||
|
{deps,[{"otpr","gmserialization",{0,1,2}},
|
||||||
|
{"otpr","eblake2",{1,0,0}},
|
||||||
|
{"otpr","getopt",{1,0,2}}]}.
|
||||||
|
{key_name,none}.
|
||||||
|
{a_email,[]}.
|
||||||
|
{c_email,[]}.
|
||||||
|
{copyright,[]}.
|
||||||
|
{file_exts,[]}.
|
||||||
|
{license,skip}.
|
||||||
|
{repo_url,"https://git.qpq.swiss/QPQ-AG/gmbytecode"}.
|
||||||
|
{tags,["gajumaru","blockchain","fate","bytecode","crypto","gm"]}.
|
||||||
|
{ws_url,[]}.
|
20
zomp_prep
Executable file
20
zomp_prep
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
# This is a small pre-packaging source generation and include correction script that should be
|
||||||
|
# run before packaging this project for use with ZX/Zomp.
|
||||||
|
|
||||||
|
rm -rf _build
|
||||||
|
rm -f src/gmb_fate_opcodes.erl src/gmb_fate_ops.erl include/gmb_fate_opcodes.hrl src/gmb_fate_asm_scan.xrl src/gmb_fate_pp.erl
|
||||||
|
make sources
|
||||||
|
cd src
|
||||||
|
for f in $(ls --ignore=gmb_fate_generate_ops.erl | grep erl)
|
||||||
|
do
|
||||||
|
echo "Updating includes in: $f"
|
||||||
|
sed -i 's/gmbytecode\/include\///g' "$f"
|
||||||
|
sed -i 's/\.\.\/include\///g' "$f"
|
||||||
|
sed -i 's/include_lib/include/g' "$f"
|
||||||
|
done
|
||||||
|
cd ..
|
||||||
|
rm -f ebin/*.beam
|
||||||
|
rm -f rebar*
|
||||||
|
rm -rf quickcheck
|
Loading…
x
Reference in New Issue
Block a user