Compare commits

...

29 Commits

Author SHA1 Message Date
cc4fd04019 Update test path
All checks were successful
Gajumaru Bytecode Tests / tests (push) Successful in 47m48s
2025-02-24 20:59:02 +09:00
97cea33be8 Dep ref update (#237)
All checks were successful
Gajumaru Bytecode Tests / tests (push) Successful in -3m36s
Reviewed-on: #237
Co-authored-by: Craig Everett <zxq9@zxq9.com>
Co-committed-by: Craig Everett <zxq9@zxq9.com>
2025-01-23 21:41:25 +09:00
1cdcb9150b Revamp (#235)
All checks were successful
Gajumaru Bytecode Tests / tests (push) Successful in -3m34s
Add Gitea tests
Rename
Remove oracle references
Package for zx

Reviewed-on: #235
Reviewed-by: dimitar.p.ivanov <dimitarivanov@qpq.swiss>
Co-authored-by: Craig Everett <zxq9@zxq9.com>
Co-committed-by: Craig Everett <zxq9@zxq9.com>
2025-01-22 21:12:54 +09:00
Hans Svensson
b47b2fe23c Merge branch 'drop_oracles' into 'master'
A few mandatory changes to FATE ops to drop Oracles

See merge request ioecs/aebytecode!117
2024-03-07 11:28:09 +00:00
Hans Svensson
5e38d6e829 A few mandatory changes to FATE ops to drop Oracles 2024-03-07 12:18:24 +01:00
Hans Svensson
009e036192
Merge pull request #116 from aeternity/add_chain_network_id
Add NETWORK_ID FATE instruction
2023-06-30 18:25:31 +02:00
Hans Svensson
37808419a8 Bump version to 3.4.0 2023-06-22 10:12:46 +02:00
Hans Svensson
f4c3782888 Patch check_numbering to allow for DBG_ at end 2023-06-22 10:08:41 +02:00
Hans Svensson
1688f85f2b Add NETWORK_ID and push DBG_* to higher opcodes 2023-06-22 08:35:32 +02:00
Gaith Hallak
b38349274f
Bump version to 3.3.0 (#115) 2023-05-28 13:40:20 +03:00
Hans Svensson
b8d593e351
Add instructions for arbitrary sized byte arrays (#114)
* Encode/decode bytes()/{bytes, any} as bytes(-1)

* Add 5 new bytes instructions

* reorder instructions and clarify some operations
2023-05-27 17:13:20 +03:00
Gaith Hallak
0f7529b26a
Introduce debugging instructions (#113)
* Add DBGLOC fate op

* Add DBGDEF and DBGUNDEF

* Change the type of arg for dbgdef and dbgundef

* Change DBGUNDEF to end_bb = true

* No safe sanity check for dbgundef

* Rename DBGDEF and DBGUNDEF to DBG_DEF and DBG_UNDEF

* Revert "No safe sanity check for dbgundef"

This reverts commit ee4949777fd988b76b9f854a2523a64a6dcdf591.

* Rename DBGLOC to DBG_LOC

* Remove column from DBG_LOC

* Add DBG_CALL and DBG_RETURN

* Update the docs for debug opcodes

* Add a DBG_CALL_R for remote calls

* Remove is_tail_call from DBG_CALL_R

* Revert "Remove is_tail_call from DBG_CALL_R"

This reverts commit a620c9c34b1c0ace77253ec0eabe6ac0b8e77ad2.

* Revert "Add a DBG_CALL_R for remote calls"

This reverts commit a336314cfc3930b348fb73352de8c108eba72973.

* Revert "Add DBG_CALL and DBG_RETURN"

This reverts commit db9766ac746b7f2d34a6f09a2f528be07b4226ea.

* Add DBG_CONTRACT op

* Upgrade aeserialization dep

* Use aeserialization v1.0.0

* Use aeserialization tag v1.0.0

* Remove debug instructions from AEVM
2023-05-25 18:09:42 +03:00
Gaith Hallak
2a0a397afa
Bump version to 3.2.0 (#112)
* Bump version to 3.2.0

* Bump version in rebar.config
2022-10-07 13:25:57 +03:00
Radosław Rowicki
093bcd6204
Merge pull request #111 from aeternity/enable-fate-code-mods
Export FATE code setters
2022-10-03 14:33:59 +02:00
radrow
6601ad2d38 Enable FATE code modifications 2022-09-16 10:54:48 +02:00
Dincho Todorov
578ebe2a8a
Switch to OTP23 (#110) 2022-08-29 14:26:17 +03:00
Radosław Rowicki
8269dbd71e
Update rebar3 and aeserialization (#109)
* Update rebar3 and aeserialization

* Version
2022-07-27 17:22:42 +04:00
Hans Svensson
08cc0a9fcd
Merge pull request #108 from aeternity/fix_doc_generation
Fix document generation script
2021-12-10 14:00:20 +01:00
Hans Svensson
84f20ab683 Fix document generation script 2021-12-10 11:53:54 +01:00
Hans Svensson
7497345928
Merge pull request #106 from aeternity/ceres_extension
Add OPCODES for bitwise operations, addr_to_byte and poseidon hash
2021-11-25 08:33:33 +01:00
Hans Svensson
822a269f75 Add OPCODES for bitwise operations, addr_to_byte and poseidon hash 2021-11-18 16:31:07 +01:00
seanhinde
0699f35b03
Merge pull request #107 from aeternity/otp-24-support
Fix OTP-24 warnings and add OTP-24 compatible rebar3
2021-11-09 16:27:23 +01:00
Sean Hinde
3829e29a63 Fix dialyzer complaint about reading core erlang 2021-11-08 17:56:57 +01:00
Sean Hinde
52e9d30f76 Fix OTP-24 warnings and add OTP-24 compatible rebar3 2021-11-08 17:35:17 +01:00
Hans Svensson
da7f00ae5d
Merge pull request #105 from aeternity/doc-gen
Ease the process of doc generation
2021-11-04 08:45:26 +01:00
radrow
326fca709f Add opcodes gen 2021-06-08 13:33:33 +02:00
radrow
e860e217a0 Better clone&create docs 2021-06-08 13:09:39 +02:00
radrow
bc48b5d62f Styling in doc gen 2021-06-08 11:43:36 +02:00
radrow
7b9c1b856b Upgrade doc generation 2021-06-08 11:26:18 +02:00
54 changed files with 747 additions and 596 deletions

View File

@ -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

View 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
View File

@ -8,21 +8,21 @@ ebin/*.beam
rel/example_project
.concrete/DEV_MODE
.rebar
aeb_asm_scan.erl
aeb_fate_asm_scan.erl
aeb_fate_asm_scan.xrl
gmb_asm_scan.erl
gmb_fate_asm_scan.erl
gmb_fate_asm_scan.xrl
_build/
aefateasm
include/aeb_fate_opcodes.hrl
src/aeb_fate_opcodes.erl
src/aeb_fate_ops.erl
src/aeb_fate_pp.erl
gmfateasm
include/gmb_fate_opcodes.hrl
src/gmb_fate_opcodes.erl
src/gmb_fate_ops.erl
src/gmb_fate_pp.erl
*.erl~
*.hrl~
*.aes~
doc
cover
aefate
gmfate
current_counterexample.eqc
.rebar3
ebin
ebin/*.beam

1
Emakefile Normal file
View File

@ -0,0 +1 @@
{"src/*", [debug_info, {i, "include/"}, {outdir, "ebin/"}]}.

View File

@ -1,5 +1,6 @@
ISC License
Copyright (c) 2025, QPQ AG
Copyright (c) 2017, aeternity developers
Permission to use, copy, modify, and/or distribute this software for any

View File

@ -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
GENERATOR_DEPS = ebin/aeb_fate_generate_ops.beam src/aeb_fate_asm_scan.template
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/gmb_fate_generate_ops.beam src/gmb_fate_asm_scan.template
REBAR ?= ./rebar3
all: local
@ -15,7 +15,8 @@ console: local
clean:
@$(REBAR) clean
rm -f $(GENERATED_SRC)
rm -f ebin/*
rm -f ebin/*.beam
rm -rf _build
dialyzer: local
@$(REBAR) as local dialyzer
@ -30,7 +31,7 @@ test: local
@$(REBAR) as local eunit
ebin/%.beam: src/%.erl
erlc -o $(dir $@) $<
erlc +debug_info -o $(dir $@) $<
$(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/

View File

@ -1,5 +1,5 @@
# aebytecode
A library and stand alone assembler for aeternity bytecode.
# gmbytecode
A library and stand alone assembler for Gajumaru bytecode.
This version supports AEVM bytecode and FATE bytecode.

View File

16
ebin/gmbytecode.app Normal file
View 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,[]}]}.

View File

@ -88,7 +88,7 @@
-define(FATE_VARIANT(Arity, Tag,T), {variant, Arity, Tag, T}).
-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
-define(FATE_INIT_ID, <<68,214,68,31>>).

View File

@ -1,15 +1,15 @@
-record(pmap, {key_t :: aeb_aevm_data:type(),
val_t :: aeb_aevm_data:type(),
-record(pmap, {key_t :: gmb_aevm_data:type(),
val_t :: gmb_aevm_data:type(),
parent :: none | 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}).
-record(maps, { maps = #{} :: #{ non_neg_integer() => #pmap{} }
, next_id = 0 :: non_neg_integer() }).
-record(heap, { maps :: #maps{},
offset :: aeb_heap:offset(),
offset :: gmb_heap:offset(),
heap :: binary() | #{non_neg_integer() => non_neg_integer()} }).

View File

@ -1,5 +1,5 @@
-define(Type(), aeb_aevm_data:type()).
-define(Type(), gmb_aevm_data:type()).
-define(TYPEREP_WORD_TAG, 0).
-define(TYPEREP_STRING_TAG, 1).

View File

@ -1,14 +1,14 @@
%%% @author Thomas Arts
%%% @doc Allow to run QuickCheck tests as eunit tests
%%% `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
%%%
%%%
%%% @end
%%% 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").
@ -20,8 +20,8 @@
quickcheck_test_() ->
{setup, fun() -> eqc:start() end,
[ ?EQC_EUNIT(aefate_code_eqc, prop_opcodes, 200),
?EQC_EUNIT(aefate_code_eqc, prop_serializes, 3000),
?EQC_EUNIT(aefate_code_eqc, prop_fail_serializes, 3000),
?EQC_EUNIT(aefate_code_eqc, prop_fuzz, 3000)
[ ?EQC_EUNIT(gmfate_code_eqc, prop_opcodes, 200),
?EQC_EUNIT(gmfate_code_eqc, prop_serializes, 3000),
?EQC_EUNIT(gmfate_code_eqc, prop_fail_serializes, 3000),
?EQC_EUNIT(gmfate_code_eqc, prop_fuzz, 3000)
]}.

View File

@ -1,14 +1,14 @@
%%% @author Thomas Arts
%%% @doc Allow to run QuickCheck tests as eunit tests
%%% `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
%%%
%%%
%%% @end
%%% 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").
@ -20,8 +20,8 @@
quickcheck_test_() ->
{setup, fun() -> eqc:start() end,
[ ?EQC_EUNIT(aefate_eqc, prop_roundtrip, 500),
?EQC_EUNIT(aefate_eqc, prop_format_scan, 2000),
?EQC_EUNIT(aefate_eqc, prop_order, 2000),
?EQC_EUNIT(aefate_eqc, prop_fuzz, 2000)
[ ?EQC_EUNIT(gmfate_eqc, prop_roundtrip, 500),
?EQC_EUNIT(gmfate_eqc, prop_format_scan, 2000),
?EQC_EUNIT(gmfate_eqc, prop_order, 2000),
?EQC_EUNIT(gmfate_eqc, prop_fuzz, 2000)
]}.

View File

@ -1,14 +1,14 @@
%%% @author Thomas Arts
%%% @doc Allow to run QuickCheck tests as eunit tests
%%% `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
%%%
%%%
%%% @end
%%% Created : 13 Dec 2018 by Thomas Arts
-module(aeb_fate_encoding_tests).
-module(gmb_fate_encoding_tests).
-include_lib("eunit/include/eunit.hrl").
@ -20,8 +20,8 @@
quickcheck_test_() ->
{setup, fun() -> eqc:start() end,
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
?EQC_EUNIT(aefate_eqc, prop_no_maps_in_keys, 1000),
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
[ ?EQC_EUNIT(gmfate_type_eqc, prop_roundtrip, 1000),
?EQC_EUNIT(gmfate_eqc, prop_serializes, 1000),
?EQC_EUNIT(gmfate_eqc, prop_no_maps_in_keys, 1000),
?EQC_EUNIT(gmfate_eqc, prop_idempotent, 1000)
]}.

View File

@ -16,7 +16,7 @@
%%% @end
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
-module(aefate_code_eqc).
-module(gmfate_code_eqc).
-include_lib("eqc/include/eqc.hrl").
@ -28,10 +28,10 @@ prop_serializes() ->
in_parallel(
?FORALL(FateCode, fate_code(0),
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]),
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(serialize, T0 / 1000,
measure(deserialize, T1 / 1000,
@ -44,20 +44,20 @@ prop_serializes() ->
prop_fail_serializes() ->
conjunction([{Failure, eqc:counterexample(
?FORALL(FateCode, fate_code(Failure),
?FORALL(Binary, catch aeb_fate_code:serialize(FateCode),
?FORALL(Binary, catch gmb_fate_code:serialize(FateCode),
is_binary(Binary))))
=/= true} || Failure <- [1, 2, 3, 4, 5] ]).
prop_fuzz() ->
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),
try aeb_fate_code:deserialize(FuzzedBin) of
try gmb_fate_code:deserialize(FuzzedBin) of
Code ->
?WHENFAIL(eqc:format("Code:\n ~p\n", [Code]),
begin
Bin1 = aeb_fate_code:serialize(Code),
Code1 = aeb_fate_code:deserialize(Bin1),
Bin1 = gmb_fate_code:serialize(Code),
Code1 = gmb_fate_code:deserialize(Bin1),
?WHENFAIL(eqc:format("Reserialized\n ~120p\n", [Bin1]),
equals(Code, Code1))
end)
@ -66,10 +66,10 @@ prop_fuzz() ->
prop_opcodes() ->
?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]),
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
_:_ ->
not lists:member(Opcode, valid_opcodes())
@ -77,7 +77,7 @@ prop_opcodes() ->
valid_opcodes() ->
[ Op || #{opcode := Op} <- aeb_fate_generate_ops:get_ops() ].
[ Op || #{opcode := Op} <- gmb_fate_generate_ops:get_ops() ].
fate_code(Failure) ->
@ -86,13 +86,13 @@ fate_code(Failure) ->
{non_empty(map(if Failure == 1 -> binary(1);
true -> binary(4) end,
{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))},
aeb_fate_code:update_annotations(
aeb_fate_code:update_symbols(
aeb_fate_code:update_functions(
aeb_fate_code:new(), FMap), SMap), AMap))).
gmb_fate_code:update_annotations(
gmb_fate_code:update_symbols(
gmb_fate_code:update_functions(
gmb_fate_code:new(), FMap), SMap), AMap))).
short_list(Max, 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)))}]).
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,
frequency(
[{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) ->
[ begin
Mnemonic = aeb_fate_opcodes:mnemonic(Op),
Arity = aeb_fate_opcodes:args(Op),
Mnemonic = gmb_fate_opcodes:mnemonic(Op),
Arity = gmb_fate_opcodes:args(Op),
case Arity of
0 -> Mnemonic;
_ -> list_to_tuple([Mnemonic |
@ -143,7 +143,7 @@ fuzz(Binary) ->
prop_small() ->
?FORALL(Value, small_fate_data(4),
begin
Bin = aeb_fate_encoding:serialize(Value),
Bin = gmb_fate_encoding:serialize(Value),
Size = byte_size(Bin),
measure(size, Size,
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
@ -151,9 +151,9 @@ prop_small() ->
end).
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
Bin = iolist_to_binary(aeb_fate_encoding:serialize_type(Type)),
Bin = iolist_to_binary(gmb_fate_encoding:serialize_type(Type)),
Size = byte_size(Bin),
measure(size, Size,
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
@ -161,7 +161,7 @@ prop_small_type() ->
end).
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) ->
?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))).

View File

@ -7,10 +7,10 @@
%%% @end
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
-module(aefate_eqc).
-module(gmfate_eqc).
-include_lib("eqc/include/eqc.hrl").
-include("../include/aeb_fate_data.hrl").
-include("../include/gmb_fate_data.hrl").
-compile([export_all, nowarn_export_all]).
@ -18,17 +18,17 @@ prop_roundtrip() ->
?FORALL(FateData, fate_data(),
measure(bytes, size(term_to_binary(FateData)),
begin
Serialized = aeb_fate_encoding:serialize(FateData),
Serialized = gmb_fate_encoding:serialize(FateData),
?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)).
prop_format_scan() ->
?FORALL(FateData, fate_data([variant, map]),
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
begin
String = aeb_fate_data:format(FateData),
{ok, _Scanned, _} = aeb_fate_asm_scan:scan(unicode:characters_to_list(String)),
String = gmb_fate_data:format(FateData),
{ok, _Scanned, _} = gmb_fate_asm_scan:scan(unicode:characters_to_list(String)),
true
end)).
@ -36,8 +36,8 @@ prop_serializes() ->
?FORALL({Data, Garbage}, {fate_data(), binary()},
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [Data]),
begin
Binary = <<(aeb_fate_encoding:serialize(Data))/binary, Garbage/binary>>,
{FateData, Rest} = aeb_fate_encoding:deserialize_one(Binary),
Binary = <<(gmb_fate_encoding:serialize(Data))/binary, Garbage/binary>>,
{FateData, Rest} = gmb_fate_encoding:deserialize_one(Binary),
measure(binary_size, size(Binary),
conjunction([{equal, equals(Data, FateData)},
{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
begin
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", []),
not HasMapInKeys)
catch error:Reason ->
@ -58,11 +58,11 @@ prop_no_maps_in_keys() ->
prop_fuzz() ->
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),
try Org = aeb_fate_encoding:deserialize(InjectedBin),
NewBin = aeb_fate_encoding:serialize(Org),
NewOrg = aeb_fate_encoding:deserialize(NewBin),
try Org = gmb_fate_encoding:deserialize(InjectedBin),
NewBin = gmb_fate_encoding:serialize(Org),
NewOrg = gmb_fate_encoding:deserialize(NewBin),
measure(success, 1,
?WHENFAIL(eqc:format("Deserialize ~p gives\n~p\nSerializes to ~p\n", [InjectedBin, Org, NewOrg]),
equals(NewBin, InjectedBin)))
@ -77,20 +77,20 @@ prop_order() ->
%% Use lt to take minimum
Min = lt_min(Items),
Max = lt_max(Items),
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])},
{asym, aeb_fate_data:lt(Min, Max) orelse Min == Max}])
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, gmb_fate_data:lt(I, Min)])},
{maximum, is_empty([ {Max, '<', I} || I<-Items, gmb_fate_data:lt(Max, I)])},
{asym, gmb_fate_data:lt(Min, Max) orelse Min == Max}])
end).
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]);
false -> lt_min([Y| Rest])
end;
lt_min([X]) -> X.
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]);
false -> lt_max([X| Rest])
end;
@ -98,8 +98,8 @@ lt_max([X]) -> X.
prop_idempotent() ->
?FORALL(Items, list({fate_data_key(), fate_data()}),
equals(aeb_fate_encoding:sort(Items),
aeb_fate_encoding:sort(aeb_fate_encoding:sort(Items)))).
equals(gmb_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)])).
fate_integer() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_integer(X))).
fate_bits() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_bits(X))).
fate_boolean() -> ?LET(X, elements([true, false]), return(aeb_fate_data:make_boolean(X))).
fate_nil() -> aeb_fate_data:make_list([]).
fate_unit() -> aeb_fate_data:make_unit().
fate_integer() -> ?LET(X, oneof([int(), largeint()]), return(gmb_fate_data:make_integer(X))).
fate_bits() -> ?LET(X, oneof([int(), largeint()]), return(gmb_fate_data:make_bits(X))).
fate_boolean() -> ?LET(X, elements([true, false]), return(gmb_fate_data:make_boolean(X))).
fate_nil() -> gmb_fate_data:make_list([]).
fate_unit() -> gmb_fate_data:make_unit().
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))}]),
return(aeb_fate_data:make_string(X))).
fate_address() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_address(X))).
fate_bytes() -> ?LET(X, non_empty(binary()), return(aeb_fate_data:make_bytes(X))).
fate_contract() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_contract(X))).
fate_oracle() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle(X))).
fate_oracle_q() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle_query(X))).
fate_channel() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_channel(X))).
return(gmb_fate_data:make_string(X))).
fate_address() -> ?LET(X, binary(256 div 8), return(gmb_fate_data:make_address(X))).
fate_bytes() -> ?LET(X, non_empty(binary()), return(gmb_fate_data:make_bytes(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(gmb_fate_data:make_oracle(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(gmb_fate_data:make_channel(X))).
fate_values(Size, 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) ->
?LET(N, choose(0, 6),
?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) ->
?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))).
fate_list(Size, Options) ->
?LET(N, frequency([{20, choose(0, 6)}, {1, choose(64 - 3, 64 + 3)}]),
?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) ->
?LET(N, choose(0, 6),
?LETSHRINK(Values, fate_values(Size, N, Options),
?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() ->
%% only #{} is allowed as cache in serialization
?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() ->
?LET(N, choose(0, 6),
?LET(Values, vector(N, ?SIZED(Size, resize(Size div 8, 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() ->
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).

View File

@ -5,7 +5,7 @@
%%% @end
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
-module(aefate_type_eqc).
-module(gmfate_type_eqc).
-include_lib("eqc/include/eqc.hrl").
@ -18,11 +18,11 @@ prop_roundtrip() ->
?FORALL(FateType, fate_type(),
collect(kind(FateType),
begin
Serialized = aeb_fate_encoding:serialize_type(FateType),
Serialized = gmb_fate_encoding:serialize_type(FateType),
BinSerialized = list_to_binary(Serialized),
?WHENFAIL(eqc:format("Serialized ~p to ~p (~p)~n", [FateType, Serialized, BinSerialized]),
begin
{Type, <<>>} = aeb_fate_encoding:deserialize_type(BinSerialized),
{Type, <<>>} = gmb_fate_encoding:deserialize_type(BinSerialized),
equals(Type, FateType)
end)
end)).

View File

@ -5,14 +5,14 @@
{erl_opts, [debug_info]}.
{deps, [ {eblake2, "1.0.0"}
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
{ref, "47aaa8f"}}}
, {gmserialization, {git, "https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref, "9d2ecc00d32ea295309563e54a81636ecb597e96"}}}
, {getopt, "1.0.1"}
]}.
{escript_incl_apps, [aebytecode, eblake2, aeserialization, getopt]}.
{escript_main_app, aebytecode}.
{escript_name, aefateasm}.
{escript_incl_apps, [gmbytecode, eblake2, gmserialization, getopt]}.
{escript_main_app, gmbytecode}.
{escript_name, gmfateasm}.
{escript_emu_args, "%%!"}.
{pre_hooks,
@ -29,8 +29,8 @@
]}.
{relx, [{release, {aebytecode, "2.0.1"},
[aebytecode, eblake2, getopt]},
{relx, [{release, {gmbytecode, "3.4.1"},
[gmbytecode, eblake2, getopt]},
{dev_mode, true},
{include_erts, false},
@ -39,17 +39,17 @@
{profiles, [{binary, [
{deps, [ {eblake2, "1.0.0"}
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
{ref, "47aaa8f"}}}
, {gmserialization, {git, "https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref, "9d2ecc00d32ea295309563e54a81636ecb597e96"}}}
, {getopt, "1.0.1"}
]},
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
escriptize,
"cp \"$REBAR_BUILD_DIR/bin/aefateasm\" ./aefateasm"},
"cp \"$REBAR_BUILD_DIR/bin/gmfateasm\" ./gmfateasm"},
{"win32",
escriptize,
"robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ aefateasm* "
"robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ gmfateasm* "
"/njs /njh /nfl /ndl & exit /b 0"} % silence things
]}
]},

View File

@ -1,20 +1,23 @@
{"1.1.0",
[{<<"aeserialization">>,
{git,"https://github.com/aeternity/aeserialization.git",
{ref,"47aaa8f5434b365c50a35bfd1490340b19241991"}},
{"1.2.0",
[{<<"gmserialization">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref,"9d2ecc00d32ea295309563e54a81636ecb597e96"}},
0},
{<<"base58">>,
{git,"https://github.com/aeternity/erl-base58.git",
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
1},
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
{<<"enacl">>,
{git,"https://github.com/aeternity/enacl.git",
{ref,"26180f42c0b3a450905d2efd8bc7fd5fd9cece75"}},
{git,"https://git.qpq.swiss/QPQ-AG/enacl.git",
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
1},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
[
{pkg_hash,[
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]}
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
{pkg_hash_ext,[
{<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>},
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
].

BIN
rebar3

Binary file not shown.

View File

@ -1,13 +1,16 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% Encode and decode data and function calls according to
%%% Sophia-AEVM-ABI
%%% @end
%%% Updated : 22 Jan 2025
%%% Created : 25 Jan 2018
%%%
%%%-------------------------------------------------------------------
-module(aeb_aevm_abi).
-module(gmb_aevm_abi).
-vsn("3.4.1").
-define(HASH_SIZE, 32).
-export([ create_calldata/4
@ -25,7 +28,7 @@
-type hash() :: <<_:256>>. %% 256 = ?HASH_SIZE * 8.
-type function_name() :: binary(). %% String
-type typerep() :: aeb_aevm_data:type().
-type typerep() :: gmb_aevm_data:type().
-type function_type_info() :: { FunctionHash :: hash()
, FunctionName :: function_name()
, Payable :: boolean()
@ -50,7 +53,7 @@ create_calldata(FunName, Args, ArgTypes0, RetType) ->
ArgTypes = {tuple, ArgTypes0},
<<TypeHashInt:?HASH_SIZE/unit:8>> =
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}.
-spec check_calldata(binary(), type_info(), boolean()) ->
@ -73,7 +76,7 @@ check_calldata(Hash, CallData, TypeInfo, true) ->
check_calldata(Hash, CallData, TypeInfo, false) ->
case typereps_from_type_hash(Hash, TypeInfo) of
{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, {tuple, [word, ArgType]}, OutType};
{error, _} ->
@ -90,7 +93,7 @@ check_calldata(Hash, CallData, TypeInfo, false) ->
-spec get_function_hash_from_calldata(CallData::binary()) ->
{ok, binary()} | {error, term()}.
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>>};
{error, _} = Error -> Error
end.
@ -105,15 +108,15 @@ function_type_info(Name, Payable, ArgTypes, OutType) ->
{ function_type_hash(Name, ArgType, OutType)
, Name
, Payable
, aeb_heap:to_binary(ArgType)
, aeb_heap:to_binary(OutType)
, gmb_heap:to_binary(ArgType)
, gmb_heap:to_binary(OutType)
}.
-spec function_type_hash(function_name(), typerep(), typerep()) -> hash().
function_type_hash(Name, ArgType, OutType) when is_binary(Name) ->
Bin = iolist_to_binary([ Name
, aeb_heap:to_binary(ArgType)
, aeb_heap:to_binary(OutType)
, gmb_heap:to_binary(ArgType)
, gmb_heap:to_binary(OutType)
]),
%% Calculate a 256 bit digest BLAKE2b hash value of a binary
{ok, Hash} = eblake2:blake2b(?HASH_SIZE, Bin),
@ -132,7 +135,7 @@ arg_typerep_from_function(Function, TypeInfo) ->
end.
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};
{error,_} -> {error, bad_type_data}
end.
@ -150,7 +153,7 @@ typereps_from_type_hash(TypeHash, TypeInfo) ->
end.
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};
{_, _} -> {error, bad_type_data}
end.

View File

@ -1,4 +1,5 @@
-module(aeb_aevm_data).
-module(gmb_aevm_data).
-vsn("3.4.1").
-export_type([data/0,
type/0,

View File

@ -1,4 +1,5 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Assembler for aevm machine code.
%%%
@ -25,17 +26,19 @@
%%% 4. labels as descibed above.
%%%
%%% @end
%%% Updated : 22 Jan 2025
%%% Created : 21 Dec 2017
%%%-------------------------------------------------------------------
-module(aeb_asm).
-module(gmb_asm).
-vsn("3.4.1").
-export([ file/2
, pp/1
, to_hexstring/1
]).
-include_lib("aebytecode/include/aeb_opcodes.hrl").
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
pp(Asm) ->
@ -47,10 +50,10 @@ format(Asm) -> format(Asm, 0).
format([{comment, Comment} | Rest], Address) ->
";; " ++ Comment ++ "\n" ++ format(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
true ->
Arity = aeb_opcodes:op_size(Op) - 1,
Arity = gmb_opcodes:op_size(Op) - 1,
{Args, Code} = get_args(Arity, Rest),
" " ++ atom_to_list(Mnemonic)
++ " " ++ Args ++ "\n"
@ -72,7 +75,7 @@ get_args(N, [Arg|Code]) ->
file(Filename, Options) ->
{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
{pp_tokens, true} ->
@ -100,8 +103,8 @@ to_hexstring(ByteList) ->
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
OpCode = aeb_opcodes:m_to_op(Op),
OpSize = aeb_opcodes:op_size(OpCode),
OpCode = gmb_opcodes:m_to_op(Op),
OpSize = gmb_opcodes:op_size(OpCode),
to_bytecode(Rest, Address + OpSize, Env, [OpCode|Code], Opts);
to_bytecode([{int,_line, Int}|Rest], Address, Env, 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.
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] >>,
ArgByteList = binary_to_list(Bin),
[OP | ArgByteList] ++ expand_args(Rest);

View File

@ -1,5 +1,6 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Assembler lexer.
%%%
@ -195,7 +196,7 @@ Erlang code.
-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).

View File

@ -1,19 +1,22 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% Prettyprint aevm machine code
%%% @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,
format/2,
format_address/1
]).
-include_lib("aebytecode/include/aeb_opcodes.hrl").
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
pp(Binary) ->
@ -26,37 +29,37 @@ format(Binary, ErrFormatFun) ->
pp(Address, [Op|Ops], Assembly, ErrFormatFun) ->
case Op of
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);
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);
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);
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);
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);
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);
X when (X >= ?PUSH1) andalso (X =< ?PUSH32) ->
Bytes = X-?PUSH1+1,
{ArgList, NextOps} = lists:split(Bytes, Ops),
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);
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);
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);
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);
_ ->
ErrFormatFun("unhandled op ~p at ~p",[Op, Address]),

View File

@ -1,13 +1,16 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc
%%% Encode and decode data and function calls according to
%%% Sophia-FATE-ABI
%%% @end
%%% Updated : 22 Jan 2025
%%% Created : 11 Jun 2019
%%%
%%%-------------------------------------------------------------------
-module(aeb_fate_abi).
-module(gmb_fate_abi).
-vsn("3.4.1").
-export([ create_calldata/2
, decode_calldata/2
@ -16,7 +19,7 @@
, get_function_type_from_function_hash/2
, abi_version/0 ]).
-include("../include/aeb_fate_data.hrl").
-include("../include/gmb_fate_data.hrl").
%%%===================================================================
%%% API
@ -29,27 +32,27 @@ abi_version() ->
-spec create_calldata(list(), [term()]) -> {ok, binary()}.
create_calldata(FunName, Args) ->
FunctionId = aeb_fate_code:symbol_identifier(list_to_binary(FunName)),
{ok, aeb_fate_encoding:serialize(
aeb_fate_data:make_tuple({FunctionId,
aeb_fate_data:make_tuple(list_to_tuple(Args))}))}.
FunctionId = gmb_fate_code:symbol_identifier(list_to_binary(FunName)),
{ok, gmb_fate_encoding:serialize(
gmb_fate_data:make_tuple({FunctionId,
gmb_fate_data:make_tuple(list_to_tuple(Args))}))}.
-spec decode_calldata(list(), binary()) -> {ok, term()} | {error, term()}.
decode_calldata(FunName, Calldata) ->
FunctionId = aeb_fate_code:symbol_identifier(list_to_binary(FunName)),
try ?FATE_TUPLE_ELEMENTS(aeb_fate_encoding:deserialize(Calldata)) of
FunctionId = gmb_fate_code:symbol_identifier(list_to_binary(FunName)),
try ?FATE_TUPLE_ELEMENTS(gmb_fate_encoding:deserialize(Calldata)) of
[FunctionId, FateArgs] -> {ok, ?FATE_TUPLE_ELEMENTS(FateArgs)};
_ -> {error, decode_error}
catch _:_ ->
{error, decode_error}
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()}.
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 = <<_:4/binary>>, FateCode) ->
Symbols = aeb_fate_code:symbols(FateCode),
Symbols = gmb_fate_code:symbols(FateCode),
case maps:get(SymbolHash, Symbols, undefined) of
undefined -> {error, no_function_matching_function_hash};
Function -> {ok, Function}
@ -58,19 +61,19 @@ get_function_name_from_function_hash(SymbolHash = <<_:4/binary>>, FateCode) ->
-spec get_function_hash_from_calldata(binary()) ->
{ok, binary()} | {error, term()}.
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};
_ -> {error, bad_calldata}
catch _:_ ->
{error, bad_calldata}
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()}.
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) ->
Functions = aeb_fate_code:functions(FateCode),
Functions = gmb_fate_code:functions(FateCode),
case maps:get(SymbolHash, Functions, undefined) of
undefined ->
{error, no_function_matching_function_hash};

View File

@ -1,4 +1,5 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc Assembler for Fate machine code.
%%% @end
@ -80,10 +81,12 @@
%%% Size: Digits
%%% Tag: Digits
%%%
%%% Updated : 22 Jan 2025
%%% Created : 21 Dec 2017
%%%-------------------------------------------------------------------
-module(aeb_fate_asm).
-module(gmb_fate_asm).
-vsn("3.4.1").
-export([ assemble_file/3
, asm_to_bytecode/2
@ -94,8 +97,8 @@
, to_asm/1
]).
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
-include_lib("aebytecode/include/aeb_fate_data.hrl").
-include_lib("gmbytecode/include/gmb_fate_opcodes.hrl").
-include_lib("gmbytecode/include/gmb_fate_data.hrl").
-define(HASH_BYTES, 32).
assemble_file(InFile, OutFile, Options) ->
@ -104,12 +107,12 @@ assemble_file(InFile, OutFile, Options) ->
ok = file:write_file(OutFile, BC).
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([{id,_,Name}, {'(',_}| Rest]) ->
{Args, []} = to_args(Rest),
aeb_fate_encoding:serialize(
gmb_fate_encoding:serialize(
{tuple, {mk_hash(Name), {tuple, list_to_tuple(Args)}}}).
@ -129,9 +132,9 @@ pp(FateCode) ->
to_asm(FateCode) ->
Functions = aeb_fate_code:functions(FateCode),
Symbols = aeb_fate_code:symbols(FateCode),
Annotations = aeb_fate_code:annotations(FateCode),
Functions = gmb_fate_code:functions(FateCode),
Symbols = gmb_fate_code:symbols(FateCode),
Annotations = gmb_fate_code:annotations(FateCode),
insert_comments(get_comments(Annotations), 1,
lists:flatten(
io_lib:format("~s",
@ -191,7 +194,7 @@ format_code([], _) ->
"";
format_code([Op|Rest], Symbols) ->
[" ",
aeb_fate_pp:format_op(Op, Symbols),
gmb_fate_pp:format_op(Op, Symbols),
"\n",
format_code(Rest, Symbols)].
@ -201,7 +204,7 @@ read_file(Filename) ->
binary_to_list(File).
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
{pp_tokens, true} ->
@ -209,7 +212,7 @@ asm_to_bytecode(AssemblerCode, Options) ->
none ->
ok
end,
Env = #{ fate_code => aeb_fate_code:new()
Env = #{ fate_code => gmb_fate_code:new()
, functions => #{}
},
@ -218,11 +221,11 @@ asm_to_bytecode(AssemblerCode, Options) ->
FunctionsMap = maps:get(functions, Env1),
Functions = [X || {_, X} <- lists:sort(maps:to_list(FunctionsMap))],
FunctionsBin = iolist_to_binary(Functions),
ByteCode = aeb_fate_code:serialize(FateCode, FunctionsBin, Options),
ByteCode = gmb_fate_code:serialize(FateCode, FunctionsBin, Options),
{Env, ByteCode}.
strip(ByteCode) ->
{Code, _Rest} = aeser_rlp:decode_one(ByteCode),
{Code, _Rest} = gmser_rlp:decode_one(ByteCode),
Code.
%% -------------------------------------------------------------------
@ -235,7 +238,7 @@ to_bytecode([{function,_line, 'FUNCTION'}|Rest], Address, Env, Code, Opts) ->
{Fun, Rest2} = to_fun_def(Rest),
to_bytecode(Rest2, Fun, Env2, [], 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([{arg,_line, N}|Rest], Address, Env, 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([{string,_line, String}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_string(String)}|Code],
[{immediate, gmb_fate_data:make_string(String)}|Code],
Opts);
to_bytecode([{object,_line, {address, Value}}|Rest],
Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_address(Value)}|Code],
[{immediate, gmb_fate_data:make_address(Value)}|Code],
Opts);
to_bytecode([{object,_line, {contract, Value}}|Rest],
Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_contract(Value)}|Code],
[{immediate, gmb_fate_data:make_contract(Value)}|Code],
Opts);
to_bytecode([{object,_line, {oracle, Value}}|Rest],
Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_oracle(Value)}|Code],
[{immediate, gmb_fate_data:make_oracle(Value)}|Code],
Opts);
to_bytecode([{object,_line, {oracle_query, Value}}|Rest],
Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_oracle_query(Value)}|Code],
[{immediate, gmb_fate_data:make_oracle_query(Value)}|Code],
Opts);
to_bytecode([{object,_line, {channel, Value}}|Rest],
Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_contract(Value)}|Code],
[{immediate, gmb_fate_data:make_contract(Value)}|Code],
Opts);
to_bytecode([{bytes,_line, Value}|Rest],
Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_bytes(Value)}|Code],
[{immediate, gmb_fate_data:make_bytes(Value)}|Code],
Opts);
to_bytecode([{contract_bytearray,_line, FateCode}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env,
[{immediate, aeb_fate_data:make_contract_bytearray(FateCode)}|Code],
[{immediate, gmb_fate_data:make_contract_bytearray(FateCode)}|Code],
Opts);
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
{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([{'(',_line}|Rest], Address, Env, Code, Opts) ->
{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([{start_variant,_line}|_] = Tokens, Address, Env, Code, Opts) ->
{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([{typerep,_line}|Rest], Address, Env, Code, Opts) ->
{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([{bits,_line, Bits}|Rest], Address, Env, Code, Opts) ->
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) ->
Env2 = insert_annotation(comment, Line, Comment, Env),
@ -356,7 +359,7 @@ parse_tuple(Tokens) ->
parse_variant([{start_variant,_line}
, {'[', _line}
, {'[', _}
| Rest]) ->
{Arities, Rest2} = parse_list(Rest),
%% Make sure Arities is a list of bytes.
@ -364,7 +367,7 @@ parse_variant([{start_variant,_line}
is_integer(A), A < 256],
[{'|',_}
, {int,_line, Tag}
, {int,_, Tag}
, {'|',_}
, {'(',_} | Rest3] = Rest2,
{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]) ->
{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]) ->
{aeb_fate_data:make_bits(Bits), Rest};
{gmb_fate_data:make_bits(Bits), Rest};
parse_value([{start_variant,_line}|_] = 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};
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]) ->
{aeb_fate_data:make_address(Address), Rest};
{gmb_fate_data:make_address(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]) ->
{aeb_fate_data:make_oracle(Address), Rest};
{gmb_fate_data:make_oracle(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]) ->
{aeb_fate_data:make_channel(Address), Rest};
{gmb_fate_data:make_channel(Address), 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]) ->
{aeb_fate_data:make_signature(Hash), Rest};
{gmb_fate_data:make_signature(Hash), Rest};
parse_value([{typerep,_line} | Rest]) ->
to_type(Rest).
@ -485,20 +488,20 @@ insert_fun(none, [], Env) -> Env;
insert_fun({NameString, ArgType, RetType}, Code, #{ fate_code := FateCode
, functions := Funs} = Env) ->
Name = list_to_binary(NameString),
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}),
FunByteCode = [?FUNCTION, Id, aeb_fate_encoding:serialize(0), SigByteCode, BodyByteCode],
{FateCode1, Id} = gmb_fate_code:insert_symbol(Name, FateCode),
BodyByteCode = gmb_fate_code:serialize_code(lists:reverse(Code)),
SigByteCode = gmb_fate_code:serialize_signature({ArgType, RetType}),
FunByteCode = [?FUNCTION, Id, gmb_fate_encoding:serialize(0), SigByteCode, BodyByteCode],
Env#{ functions => Funs#{ Id => FunByteCode }
, fate_code => FateCode1}.
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 }
, Id}.
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}.
mk_hash(Id) ->

View File

@ -1,6 +1,7 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2019, aeternity Anstalt
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc
%%% Handling FATE code.
%%% @end
@ -100,7 +101,7 @@ Erlang code.
-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).
@ -115,12 +116,12 @@ parse_hash("#" ++ Chars) ->
base64:decode(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
end.
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};
{contract_pubkey, Bin} -> {contract, Bin};
{oracle_pubkey, Bin} -> {oracle, Bin};

View File

@ -1,11 +1,13 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc
%%% ADT for fate byte code/fate code
%%% @end
%%%
%%%-------------------------------------------------------------------
-module(aeb_fate_code).
-module(gmb_fate_code).
-vsn("3.4.1").
-export([ annotations/1
, deserialize/1
@ -24,14 +26,12 @@
, symbols/1
]).
-include("../include/aeb_fate_opcodes.hrl").
-include("../include/aeb_fate_data.hrl").
-include("../include/gmb_fate_opcodes.hrl").
-include("../include/gmb_fate_data.hrl").
-ifdef(EQC).
-export([ update_annotations/2
, update_functions/2
, update_symbols/2]).
-endif.
-record(fcode, { functions = #{} :: map()
, symbols = #{} :: map()
@ -89,8 +89,8 @@ insert_symbol(Name, #fcode{ symbols = Syms } = F) ->
end.
insert_annotation(comment =_Type, Line, Comment, FCode) ->
Key = aeb_fate_data:make_tuple({aeb_fate_data:make_string("comment"), Line}),
Value = aeb_fate_data:make_string(Comment),
Key = gmb_fate_data:make_tuple({gmb_fate_data:make_string("comment"), Line}),
Value = gmb_fate_data:make_string(Comment),
update_annotations(FCode, #{ Key => Value }).
strip_init_function(#fcode{ functions = Funs,
@ -113,9 +113,9 @@ serialize(#fcode{} = F, Options) ->
serialize(#fcode{} = F, Functions, Options) ->
SymbolTable = serialize_symbol_table(F),
Annotatations = serialize_annotations(F),
ByteCode = << (aeser_rlp:encode(Functions))/binary,
(aeser_rlp:encode(SymbolTable))/binary,
(aeser_rlp:encode(Annotatations))/binary
ByteCode = << (gmser_rlp:encode(Functions))/binary,
(gmser_rlp:encode(SymbolTable))/binary,
(gmser_rlp:encode(Annotatations))/binary
>>,
case proplists:lookup(pp_hex_string, Options) of
@ -141,20 +141,20 @@ serialize_functions(#fcode{ functions = Functions }) ->
serialize_attributes(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(payable) -> 2.
serialize_signature({Args, RetType}) ->
[aeb_fate_encoding:serialize_type({tuple, Args}) |
aeb_fate_encoding:serialize_type(RetType)].
[gmb_fate_encoding:serialize_type({tuple, Args}) |
gmb_fate_encoding:serialize_type(RetType)].
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 }) ->
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, 0, []).
@ -176,7 +176,7 @@ serialize_op(Op) ->
true -> tuple_to_list(Op);
false -> [Op]
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 }) ->
_ = [ case Def of
@ -215,12 +215,12 @@ sanity_check_op(IsLast, Op) ->
true -> tuple_to_list(Op);
false -> [Op]
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) ->
case length(Args) == aeb_fate_opcodes:args(Op) of
case length(Args) == gmb_fate_opcodes:args(Op) of
true ->
case IsLast == aeb_fate_opcodes:end_bb(Op) of
case IsLast == gmb_fate_opcodes:end_bb(Op) of
true -> ok;
false -> error({wrong_opcode_in_bb, Op})
end;
@ -271,7 +271,7 @@ pad_args(List) ->
end.
serialize_data(_, Data) ->
aeb_fate_encoding:serialize(Data).
gmb_fate_encoding:serialize(Data).
%% 00 : stack/unused (depending on instruction)
%% 01 : argN
@ -293,9 +293,9 @@ bits_to_modifier(2#00) -> stack.
%%%===================================================================
deserialize(Bytes) ->
{ByteCode, Rest1} = aeser_rlp:decode_one(Bytes),
{SymbolTable, Rest2} = aeser_rlp:decode_one(Rest1),
{Annotations, <<>>} = aeser_rlp:decode_one(Rest2),
{ByteCode, Rest1} = gmser_rlp:decode_one(Bytes),
{SymbolTable, Rest2} = gmser_rlp:decode_one(Rest1),
{Annotations, <<>>} = gmser_rlp:decode_one(Rest2),
Env = #{ function => none
, bb => 0
@ -355,7 +355,7 @@ deserialize_functions(<<Op:8, Rest/binary>>,
, current_bb_code := Code
, code := Program} = Env) ->
{Rest2, OpCode} = deserialize_op(Op, Rest, Code),
case aeb_fate_opcodes:end_bb(Op) of
case gmb_fate_opcodes:end_bb(Op) of
true ->
deserialize_functions(Rest2, Env#{ bb => BB+1
, current_bb_code => []
@ -380,8 +380,8 @@ deserialize_functions(<<>>, #{ function := {F, Attrs, Sig}
Funs#{F => {Attrs, Sig, FunctionCode}}.
deserialize_op(Op, Rest, Code) ->
OpName = aeb_fate_opcodes:mnemonic(Op),
case aeb_fate_opcodes:args(Op) of
OpName = gmb_fate_opcodes:mnemonic(Op),
case gmb_fate_opcodes:args(Op) of
0 ->
{Rest, [OpName | Code]};
N ->
@ -397,7 +397,7 @@ deserialize_n_args(N, <<M3:2, M2:2, M1:2, M0:2, Rest/binary>>) when N =< 4 ->
stack ->
{{stack, 0}, Acc};
Modifier ->
{Arg, Acc2} = aeb_fate_encoding:deserialize_one(Acc),
{Arg, Acc2} = gmb_fate_encoding:deserialize_one(Acc),
{{Modifier, Arg}, Acc2}
end
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, 0}, Acc};
Modifier ->
{Arg, Acc2} = aeb_fate_encoding:deserialize_one(Acc),
{Arg, Acc2} = gmb_fate_encoding:deserialize_one(Acc),
{{Modifier, Arg}, Acc2}
end
end, Rest, ArgMods).
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) ],
{lists:sort(Attrs), Rest}.
@ -428,16 +428,16 @@ attr(1) -> private;
attr(2) -> payable.
deserialize_signature(Binary) ->
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
{{tuple, Args}, Rest} = gmb_fate_encoding:deserialize_type(Binary),
{RetType, Rest2} = gmb_fate_encoding:deserialize_type(Rest),
{{Args, RetType}, Rest2}.
deserialize_symbols(Table) ->
?FATE_MAP_VALUE(SymbolTable) = aeb_fate_encoding:deserialize(Table),
?FATE_MAP_VALUE(SymbolTable) = gmb_fate_encoding:deserialize(Table),
SymbolTable.
deserialize_annotations(AnnotationsBin) ->
?FATE_MAP_VALUE(Annotations) = aeb_fate_encoding:deserialize(AnnotationsBin),
?FATE_MAP_VALUE(Annotations) = gmb_fate_encoding:deserialize(AnnotationsBin),
Annotations.
assert_zero([]) ->

View File

@ -1,8 +1,9 @@
%% 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_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(?FATE_BYTES(X)) -> ["#", base64:encode(X)];
format(?FATE_ADDRESS(X)) ->
["@", aeser_api_encoder:encode(account_pubkey, X)];
["@", gmser_api_encoder:encode(account_pubkey, X)];
format(?FATE_CONTRACT(X)) ->
["@", aeser_api_encoder:encode(contract_pubkey, X)];
["@", gmser_api_encoder:encode(contract_pubkey, X)];
format(?FATE_ORACLE(X)) ->
["@", aeser_api_encoder:encode(oracle_pubkey, X)];
["@", gmser_api_encoder:encode(oracle_pubkey, 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)) ->
["@", aeser_api_encoder:encode(channel, X)];
["@", gmser_api_encoder:encode(channel, X)];
format(?FATE_TYPEREP(X)) ->
["'", io_lib:format("~p", [X])];
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_bits(0, Acc) -> Acc;

View File

@ -29,7 +29,7 @@
%% * First draft of FATE serialization encoding/decoding.
%% Initial experiment with tags
%% * Second draft
%% * FATE data is now defined in aefa_data.erl
%% * FATE data is now defined in gmfa_data.erl
%% * Third draft
%% * Added Bit strings
%%
@ -39,7 +39,8 @@
%% * Handle instructions.
%%
%% ------------------------------------------------------------------------
-module(aeb_fate_encoding).
-module(gmb_fate_encoding).
-vsn("3.4.1").
-export([ deserialize/1
, deserialize_one/1
@ -52,7 +53,7 @@
-export([sort/1]).
-endif.
-include("aeb_fate_data.hrl").
-include("gmb_fate_data.hrl").
%% Definition of tag scheme.
%% This has to follow the protocol specification.
@ -135,7 +136,7 @@
%% Serialized a Fate data value into a sequence of bytes
%% according to the Fate serialization specification.
%% 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_FALSE) -> <<?FALSE>>;
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) ->
<<?OBJECT, ?OTYPE_BYTES, (serialize(?FATE_STRING(Bytes)))/binary>>;
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) ->
<<?OBJECT, ?OTYPE_CONTRACT, (aeser_rlp:encode(Address))/binary>>;
<<?OBJECT, ?OTYPE_CONTRACT, (gmser_rlp:encode(Address))/binary>>;
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) ->
<<?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) ->
<<?OBJECT, ?OTYPE_CHANNEL, (aeser_rlp:encode(Address))/binary>>;
<<?OBJECT, ?OTYPE_CHANNEL, (gmser_rlp:encode(Address))/binary>>;
serialize(?FATE_TUPLE(T)) when size(T) > 0 ->
S = size(T),
L = tuple_to_list(T),
@ -209,7 +210,7 @@ serialize(?FATE_VARIANT(Arities, Tag, Values)) ->
, is_tuple(Values) ->
Arity = lists:nth(Tag+1, Arities),
if size(Values) =:= Arity ->
EncodedArities = aeser_rlp:encode(list_to_binary(Arities)),
EncodedArities = gmser_rlp:encode(list_to_binary(Arities)),
<<?VARIANT,
EncodedArities/binary,
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(boolean) -> [?TYPE_BOOLEAN];
serialize_type(any) -> [?TYPE_ANY];
@ -238,6 +239,8 @@ serialize_type({tuple, Ts}) ->
N when N =< 255 ->
[?TYPE_TUPLE, N | [serialize_type(T) || T <- Ts]]
end;
serialize_type({bytes, any}) ->
[?TYPE_BYTES | binary_to_list(serialize_integer(-1))];
serialize_type({bytes, N}) when 0 =< N ->
[?TYPE_BYTES | binary_to_list(serialize_integer(N))];
serialize_type(address) -> [?TYPE_OBJECT, ?OTYPE_ADDRESS];
@ -257,7 +260,7 @@ serialize_type({variant, ListOfVariants}) ->
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_BOOLEAN, Rest/binary>>) -> {boolean, Rest};
deserialize_type(<<?TYPE_ANY, Rest/binary>>) -> {any, Rest};
@ -270,8 +273,12 @@ deserialize_type(<<?TYPE_TUPLE, N, Rest/binary>>) ->
{{tuple, Ts}, Rest2};
deserialize_type(<<?TYPE_BYTES, Rest/binary>>) ->
{N, Rest2} = deserialize_one(Rest),
true = is_integer(N) andalso N >= 0,
{{bytes, N}, Rest2};
true = is_integer(N),
if N == -1 ->
{{bytes, any}, Rest2};
0 =< N ->
{{bytes, N}, Rest2}
end;
deserialize_type(<<?TYPE_OBJECT, ObjectType, Rest/binary>>) ->
case ObjectType of
?OTYPE_ADDRESS -> {address, Rest};
@ -310,13 +317,13 @@ deserialize_types(N, Binary, Acc) ->
%% -----------------------------------------------------
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,
%% so <<129, 0>> is <<0>> and <<130, 0, 0>> is <<0, 0>>
rlp_decode_int(Binary) ->
{Bin1, Rest} = aeser_rlp:decode_one(Binary),
{Bin1, Rest} = gmser_rlp:decode_one(Binary),
Int = binary:decode_unsigned(Bin1),
ReEncode = rlp_encode_int(Int),
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>>
end.
-spec deserialize(binary()) -> aeb_fate_data:fate_type().
-spec deserialize(binary()) -> gmb_fate_data:fate_type().
deserialize(B) ->
{T, <<>>} = deserialize2(B),
T.
@ -400,7 +407,7 @@ deserialize2(<<?OBJECT, ?OTYPE_BYTES, Rest/binary>>) ->
true = ?IS_FATE_STRING(String),
{?FATE_BYTES(?FATE_STRING_VALUE(String)), Rest2};
deserialize2(<<?OBJECT, ObjectType, Rest/binary>>) ->
{A, Rest2} = aeser_rlp:decode_one(Rest),
{A, Rest2} = gmser_rlp:decode_one(Rest),
Val =
case ObjectType of
?OTYPE_ADDRESS -> ?FATE_ADDRESS(A);
@ -449,7 +456,7 @@ deserialize2(<<?MAP_ID, Rest/binary>>) ->
{Id, Rest1} = rlp_decode_int(Rest),
{?FATE_STORE_MAP(#{}, Id), Rest1};
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),
Size = length(Arities),
if Tag > Size -> exit({too_large_tag_in_variant, Tag, Size});
@ -496,7 +503,7 @@ sort_and_check(List) ->
sort(KVList) ->
SortFun = fun({K1, _}, {K2, _}) ->
aeb_fate_data:elt(K1, K2)
gmb_fate_data:elt(K1, K2)
end,
lists:sort(SortFun, KVList).

View 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]
).

View File

@ -1,8 +1,8 @@
-module(aeb_fate_generate_ops).
-module(gmb_fate_generate_ops).
-vsn("3.4.1").
-export([ gen_and_halt/1
, generate/0
, generate_documentation/1
, get_ops/0
, test_asm_generator/1 ]).
@ -19,12 +19,12 @@ generate(Src, Include) ->
check_defs(ops_defs()),
Ops = get_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_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops),
generate_code_ops(aeb_fate_ops, Src, Ops),
generate_scanner("aeb_fate_asm_scan.template", "aeb_fate_asm_scan.xrl", Src, Ops),
gen_asm_pp(aeb_fate_pp, Src, Ops).
generate_opcodes_ops(gmb_fate_opcodes, HrlFile, Src, Ops),
generate_code_ops(gmb_fate_ops, Src, Ops),
generate_scanner("gmb_fate_asm_scan.template", "gmb_fate_asm_scan.xrl", Src, Ops),
gen_asm_pp(gmb_fate_pp, Src, Ops).
check_defs(List) ->
true = check_numbering(0, lists:keysort(2, List)).
@ -32,7 +32,11 @@ check_defs(List) ->
check_numbering(N, [T|Rest]) ->
OpCode = element(2, T),
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);
_ when OpCode < N -> {duplicate_opcode, OpCode};
_ 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}]).
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."}
, { '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."}
@ -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."}
%% 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."}
, { '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."}
, { '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"}
%% Intentional gap (was oracles)
, { '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_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"}
, { '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"}
, { '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)"}
%% Intentional gap (was oracles)
, { '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_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"}
@ -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"}
, { '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."}
, { '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."}
, { '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."}
, { '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_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"}
, { '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)."}
, { '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 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 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). 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."}
, { '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."}
, { '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."}
@ -314,7 +334,7 @@ generate_code_ops(Modulename, SrcDir, Ops) ->
" and documentation for Fate "
"instructions.\n")]),
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"
"-type fate_arg_immediate(T) :: {immediate, T}.\n"
"-type fate_arg_var() :: {var, integer()}.\n"
@ -324,7 +344,7 @@ generate_code_ops(Modulename, SrcDir, Ops) ->
" | fate_arg_var()\n"
" | fate_arg_arg()\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, "-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([a]) -> "fate_arg()";
gen_arg_type_specs([is]) -> "aeb_fate_data:fate_string()";
gen_arg_type_specs([ii]) -> "aeb_fate_data:fate_integer()";
gen_arg_type_specs([li]) -> "[aeb_fate_data:fate_integer()]";
gen_arg_type_specs([t]) -> "aeb_fate_data:fate_type_type()";
gen_arg_type_specs([is]) -> "gmb_fate_data:fate_string()";
gen_arg_type_specs([ii]) -> "gmb_fate_data:fate_integer()";
gen_arg_type_specs([li]) -> "[gmb_fate_data:fate_integer()]";
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([is | Args]) -> "aeb_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([li | Args]) -> "[aeb_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([is | Args]) -> "gmb_fate_data:fate_string(), " ++ 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]) -> "[gmb_fate_data:fate_integer()], " ++ 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(_, []) ->
@ -409,7 +429,7 @@ ops_exports(Module, HrlFile, Exports) ->
lists:flatten(io_lib:format(
"-module(~w).\n\n"
"-export([ ~s ]).\n\n"
"-include_lib(\"aebytecode/" ++ HrlFile ++"\").\n\n"
"-include_lib(\"gmbytecode/" ++ HrlFile ++"\").\n\n"
"%%====================================================================\n"
"%% API\n"
"%%====================================================================\n",
@ -449,7 +469,7 @@ prelude(Doc) ->
"%%%\n"
"%%% === === N O T E : This file is generated do not edit. === ===\n"
"%%%\n"
"%%% Source is in aeb_fate_generate_ops.erl\n"
"%%% Source is in gmb_fate_generate_ops.erl\n"
"%%% @doc\n"
"%%% "++Doc++
"%%% @end\n"
@ -498,10 +518,10 @@ expand_types([T]) -> expand_type(T);
expand_types([T|Ts]) ->expand_type(T) ++ ", " ++ expand_types(Ts).
expand_type(a) -> "fate_arg()";
expand_type(is) -> "fate_arg_immediate(aeb_fate_data:fate_string())";
expand_type(ii) -> "fate_arg_immediate(aeb_fate_data:fate_integer())";
expand_type(li) -> "fate_arg_immediate([aeb_fate_data:fate_integer()])";
expand_type(t) -> "aeb_fate_data:fate_type_type()".
expand_type(is) -> "fate_arg_immediate(gmb_fate_data:fate_string())";
expand_type(ii) -> "fate_arg_immediate(gmb_fate_data:fate_integer())";
expand_type(li) -> "fate_arg_immediate([gmb_fate_data:fate_integer()])";
expand_type(t) -> "gmb_fate_data:fate_type_type()".
generate_scanner(TemplateFile, Outfile, Path, Ops) ->
{ok, Template} = file:read_file(filename:join(Path,TemplateFile)),
@ -521,8 +541,8 @@ insert_tokens_in_template(<<"%%% ###REPLACEWITHNOTE###", Rest/binary >>, Tokens)
"%%%\n"
"%%% === === N O T E : This file is generated do not edit. === ===\n"
"%%%\n"
"%%% Source is in aeb_fate_generate_ops.erl\n"
"%%% and aeb_fate_asm_scan.template"
"%%% Source is in gmb_fate_generate_ops.erl\n"
"%%% and gmb_fate_asm_scan.template"
| insert_tokens_in_template(Rest, Tokens)];
insert_tokens_in_template(<<B,Rest/binary>>, Tokens) ->
[B|insert_tokens_in_template(Rest, Tokens)].
@ -538,9 +558,9 @@ gen_asm_pp(Module, Path, Ops) ->
io:format(File,
"-export([format_op/2]).\n\n"
"format_arg(li, {immediate, LI}) ->\n"
" aeb_fate_data:format(LI);\n"
" gmb_fate_data:format(LI);\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, {var, N}) when N < 0 -> io_lib:format(\"store~~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() ++ " ) |)"
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".

View File

@ -1,4 +1,5 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc
%%% Functions for manipulating FATE maps. In particular for mediating
@ -6,9 +7,10 @@
%%% fully or partially saved in the contract store.
%%% @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
, has_store_maps/1
@ -31,11 +33,11 @@
-define(STORE_MAP_THRESHOLD, 100).
-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 id() :: integer().
-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 --------------------------------------------------
@ -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) ->
{Used1, KVs, Maps1} = allocate_store_maps_m(Used, ?FATE_MAP_VALUE(Val), Maps),
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};
false ->
{Id, Used2} = next_id(Used1),
@ -97,7 +99,7 @@ allocate_store_maps_m(Used, Val, 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().
unfold_store_maps(_Unfold, ?FATE_MAP_TOMBSTONE = Val) -> Val;

View File

@ -1,4 +1,5 @@
-module(aeb_heap).
-module(gmb_heap).
-vsn("3.4.1").
-export([ to_binary/1
, to_binary/2
@ -22,8 +23,8 @@
-export_type([binary_value/0, heap_value/0, offset/0, heap_fragment/0]).
-include_lib("aebytecode/include/aeb_typerep_def.hrl").
-include_lib("aebytecode/include/aeb_heap.hrl").
-include_lib("gmbytecode/include/gmb_typerep_def.hrl").
-include_lib("gmbytecode/include/gmb_heap.hrl").
-type word() :: non_neg_integer().
-type pointer() :: word().
@ -112,7 +113,7 @@ pmap_size(#pmap{data = Data}) when is_map(Data) ->
%% -- 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
%% types) or a pointer to the value (for boxed types).
to_binary(Data) ->
@ -131,10 +132,10 @@ to_binary1(Data,_Address) when is_integer(Data) ->
{Data,<<>>};
to_binary1(Data, Address) when is_binary(Data) ->
%% 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>>};
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>>};
to_binary1(none, Address) -> to_binary1({variant, 0, []}, Address);
to_binary1({some, Value}, Address) -> to_binary1({variant, 1, [Value]}, Address);

View File

@ -1,12 +1,15 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc
%%% Memory speifics that compiler and VM need to agree upon
%%% @end
%%% Updated : 22 Jan 2025
%%% Created : 19 Dec 2018
%%%-------------------------------------------------------------------
-module(aeb_memory).
-module(gmb_memory).
-vsn("3.4.1").
-export([binary_to_words/1]).

View File

@ -1,12 +1,15 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% Opcodes
%%% @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
, mnemonic/1
@ -17,7 +20,7 @@
, swap/1
]).
-include_lib("aebytecode/include/aeb_opcodes.hrl").
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
%%====================================================================

View File

@ -1,18 +1,21 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc
%%% Handle interaction with the aeternity chain
%%% Handle interaction with the gmternity chain
%%% through calls to AEternity primitive operations at address 0.
%%% @end
%%% Updated : 22 Jan 2025
%%% Created : 18 Dec 2018
%%%-------------------------------------------------------------------
-module(aeb_primops).
-module(gmb_primops).
-vsn("3.4.1").
-export([ is_local_primop_op/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_CRYPTO_RANGE(Op) -> true;

View File

@ -1,12 +1,12 @@
{application, aebytecode,
[{description, "Bytecode definitions, serialization and deserialization for aeternity."},
{vsn, "2.1.0"},
{application, gmbytecode,
[{description, "Bytecode definitions, serialization and deserialization for the Gajumaru."},
{vsn, "3.4.1"},
{registered, []},
{applications,
[kernel,
stdlib,
eblake2,
aeserialization,
gmserialization,
getopt
]},
{env,[]},

View File

@ -1,4 +1,5 @@
-module(aefateasm).
-module(gmfateasm).
-vsn("3.4.1").
-export([main/1]).
@ -9,7 +10,7 @@
, {outfile, $o, "out", string, "Output file (experimental)"} ]).
usage() ->
getopt:usage(?OPT_SPEC, "aefateasm").
getopt:usage(?OPT_SPEC, "gmfateasm").
main(Args) ->
case getopt:parse(?OPT_SPEC, Args) of
@ -43,8 +44,8 @@ assemble(File, Opts) ->
Verbose = proplists:get_value(verbose, Opts, false),
case proplists:get_value(outfile, Opts, undefined) of
undefined ->
Asm = aeb_fate_asm:read_file(File),
{Env, BC} = aeb_fate_asm:asm_to_bytecode(Asm, Opts),
Asm = gmb_fate_asm:read_file(File),
{Env, BC} = gmb_fate_asm:asm_to_bytecode(Asm, Opts),
case Verbose of
true ->
io:format("Env: ~0p~n", [Env]);
@ -52,6 +53,6 @@ assemble(File, Opts) ->
end,
io:format("Code: ~0p~n", [BC]);
OutFile ->
aeb_fate_asm:assemble_file(File, OutFile, Opts)
gmb_fate_asm:assemble_file(File, OutFile, Opts)
end.

View File

@ -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>>)
].

View File

@ -62,13 +62,13 @@ id_local: JUMPDEST
JUMP
;; 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.
;; 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.
;; 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().

View File

@ -5,4 +5,4 @@ FUNCTION id(integer) -> integer
;; Test the code from the shell
;; _build/default/rel/aessembler/bin/aessembler console
;; aeb_aefa:file("../../../../test/asm_code/identity.fate", []).
;; gmb_gmfa:file("../../../../test/asm_code/identity.fate", []).

View File

@ -68,9 +68,6 @@ FUNCTION tuple() : {tuple, [integer, boolean, string, {tuple, [integer, integer]
FUNCTION address() : address
RETURNR @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
FUNCTION oracle() : oracle
RETURNR @ok_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
FUNCTION contract() : contract
RETURNR @ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv

View File

@ -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

View File

@ -37,5 +37,5 @@ FUNCTION tailcall(integer) -> integer
;; Test the code from the shell
;; _build/default/rel/aessembler/bin/aessembler console
;; aeb_aefa: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, []).
;; gmb_gmfa:file("../../../../test/asm_code/test.fate", []).
;; 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, []).

View File

@ -1,12 +1,13 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc Basic tests for Fate data
%%% @end
%%%-------------------------------------------------------------------
-module(aeb_data_test).
-module(gmb_data_test).
-include_lib("eunit/include/eunit.hrl").
format_integer_test() ->
"0" = aeb_fate_data:format(0).
"0" = gmb_fate_data:format(0).

View File

@ -1,19 +1,20 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc Basic tests for Fate serialization
%%%
%%% To run:
%%% TEST=aeb_fate_asm_test rebar3 eunit
%%% TEST=gmb_fate_asm_test rebar3 eunit
%%%
%%% @end
%%%-------------------------------------------------------------------
-module(aeb_fate_asm_test).
-module(gmb_fate_asm_test).
-include_lib("eunit/include/eunit.hrl").
asm_path() ->
filename:join(code:lib_dir(aebytecode, test), "asm_code").
filename:join(code:lib_dir(gmbytecode, test), "asm_code").
file_path(File) ->
@ -21,11 +22,11 @@ file_path(File) ->
read_file(File) ->
FilePath = file_path(File),
Asm = aeb_fate_asm:read_file(FilePath),
Asm = gmb_fate_asm:read_file(FilePath),
Asm.
assemble(Asm) ->
aeb_fate_asm:asm_to_bytecode(Asm, []).
gmb_fate_asm:asm_to_bytecode(Asm, []).
asm_disasm_idenity_test() ->
check_roundtrip(identity).
@ -48,19 +49,18 @@ sources() ->
, "mapofmap"
, "immediates"
, "names"
, "oracles"
, "meta"
].
check_roundtrip(File) ->
AssemblerCode = read_file(File),
{_Env, ByteCode} = assemble(AssemblerCode),
FateCode = aeb_fate_code:deserialize(ByteCode),
DissasmCode = aeb_fate_asm:to_asm(FateCode),
FateCode = gmb_fate_code:deserialize(ByteCode),
DissasmCode = gmb_fate_asm:to_asm(FateCode),
{_Env2, ByteCode2} = assemble(DissasmCode),
ByteCode3 = aeb_fate_code:serialize(FateCode),
Code1 = aeb_fate_asm:strip(ByteCode),
Code2 = aeb_fate_asm:strip(ByteCode2),
Code3 = aeb_fate_asm:strip(ByteCode3),
ByteCode3 = gmb_fate_code:serialize(FateCode),
Code1 = gmb_fate_asm:strip(ByteCode),
Code2 = gmb_fate_asm:strip(ByteCode2),
Code3 = gmb_fate_asm:strip(ByteCode3),
?assertEqual(Code1, Code2),
?assertEqual(Code1, Code3).

View 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>>)
].

View File

@ -1,4 +1,4 @@
-module(aebytecode_SUITE).
-module(gmbytecode_SUITE).
%% common_test exports
-export([ all/0 ]).
@ -12,8 +12,8 @@ all() ->
[ roundtrip_identy ].
roundtrip_identy(_Cfg) ->
CodeDir = code:lib_dir(aebytecode, test),
FileName = filename:join(CodeDir, "asm_code/identity.aesm"),
Code = aeb_asm:file(FileName, []),
ct:log("Code ~p:~n~s~n", [FileName, aeb_disassemble:format(Code, fun io:format/2)]),
CodeDir = code:lib_dir(gmbytecode, test),
FileName = filename:join(CodeDir, "asm_code/identity.gmsm"),
Code = gmb_asm:file(FileName, []),
ct:log("Code ~p:~n~s~n", [FileName, gmb_disassemble:format(Code, fun io:format/2)]),
ok.

19
zomp.meta Normal file
View 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
View 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