Merge pull request #223 from aeternity/GH-202-Auth_tx_introspection

Gh 202 auth tx introspection
This commit is contained in:
Hans Svensson 2020-02-11 15:48:46 +01:00 committed by GitHub
commit 6682b24156
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 162 additions and 9 deletions

View File

@ -2,7 +2,7 @@
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"8a9c9de"}}} {deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"ff5a4c7"}}}
, {getopt, "1.0.1"} , {getopt, "1.0.1"}
, {eblake2, "1.0.0"} , {eblake2, "1.0.0"}
, {jsx, {git, "https://github.com/talentdeficit/jsx.git", , {jsx, {git, "https://github.com/talentdeficit/jsx.git",

View File

@ -1,7 +1,7 @@
{"1.1.0", {"1.1.0",
[{<<"aebytecode">>, [{<<"aebytecode">>,
{git,"https://github.com/aeternity/aebytecode.git", {git,"https://github.com/aeternity/aebytecode.git",
{ref,"8a9c9dec956b1d2322b38490b2759e53a91affab"}}, {ref,"ff5a4c7dd54ec22d30f16152341fb9ffcd6cc135"}},
0}, 0},
{<<"aeserialization">>, {<<"aeserialization">>,
{git,"https://github.com/aeternity/aeserialization.git", {git,"https://github.com/aeternity/aeserialization.git",

View File

@ -397,6 +397,15 @@ global_env() ->
G1 = {tuple_t, Ann, [Fp, Fp, Fp]}, G1 = {tuple_t, Ann, [Fp, Fp, Fp]},
G2 = {tuple_t, Ann, [Fp2, Fp2, Fp2]}, G2 = {tuple_t, Ann, [Fp2, Fp2, Fp2]},
GT = {tuple_t, Ann, lists:duplicate(12, Fp)}, GT = {tuple_t, Ann, lists:duplicate(12, Fp)},
Tx = {qid, Ann, ["Chain", "tx"]},
GAMetaTx = {qid, Ann, ["Chain", "ga_meta_tx"]},
BaseTx = {qid, Ann, ["Chain", "base_tx"]},
PayForTx = {qid, Ann, ["Chain", "paying_for_tx"]},
FldT = fun(Id, T) -> {field_t, Ann, {id, Ann, Id}, T} end,
TxFlds = [{"paying_for", Option(PayForTx)}, {"ga_metas", List(GAMetaTx)},
{"actor", Address}, {"fee", Int}, {"ttl", Int}, {"tx", BaseTx}],
TxType = {record_t, [FldT(N, T) || {N, T} <- TxFlds ]},
Fee = Int, Fee = Int,
[A, Q, R, K, V] = lists:map(TVar, ["a", "q", "r", "k", "v"]), [A, Q, R, K, V] = lists:map(TVar, ["a", "q", "r", "k", "v"]),
@ -435,8 +444,36 @@ global_env() ->
{"timestamp", Int}, {"timestamp", Int},
{"block_height", Int}, {"block_height", Int},
{"difficulty", Int}, {"difficulty", Int},
{"gas_limit", Int}]) {"gas_limit", Int},
, types = MkDefs([{"ttl", 0}]) }, %% Tx constructors
{"GAMetaTx", Fun([Address, Int], GAMetaTx)},
{"PayingForTx", Fun([Address, Int], PayForTx)},
{"SpendTx", Fun([Address, Int, String], BaseTx)},
{"OracleRegisterTx", BaseTx},
{"OracleQueryTx", BaseTx},
{"OracleResponseTx", BaseTx},
{"OracleExtendTx", BaseTx},
{"NamePreclaimTx", BaseTx},
{"NameClaimTx", Fun([String], BaseTx)},
{"NameUpdateTx", Fun([Hash], BaseTx)},
{"NameRevokeTx", Fun([Hash], BaseTx)},
{"NameTransferTx", Fun([Address, Hash], BaseTx)},
{"ChannelCreateTx", Fun([Address], BaseTx)},
{"ChannelDepositTx", Fun([Address, Int], BaseTx)},
{"ChannelWithdrawTx", Fun([Address, Int], BaseTx)},
{"ChannelForceProgressTx", Fun([Address], BaseTx)},
{"ChannelCloseMutualTx", Fun([Address], BaseTx)},
{"ChannelCloseSoloTx", Fun([Address], BaseTx)},
{"ChannelSlashTx", Fun([Address], BaseTx)},
{"ChannelSettleTx", Fun([Address], BaseTx)},
{"ChannelSnapshotSoloTx", Fun([Address], BaseTx)},
{"ContractCreateTx", Fun([Int], BaseTx)},
{"ContractCallTx", Fun([Address, Int], BaseTx)},
{"GAAttachTx", BaseTx}
])
, types = MkDefs([{"ttl", 0}, {"tx", {[], TxType}},
{"base_tx", 0},
{"paying_for_tx", 0}, {"ga_meta_tx", 0}]) },
ContractScope = #scope ContractScope = #scope
{ funs = MkDefs( { funs = MkDefs(
@ -543,7 +580,8 @@ global_env() ->
%% Authentication %% Authentication
AuthScope = #scope AuthScope = #scope
{ funs = MkDefs( { funs = MkDefs(
[{"tx_hash", Option(Hash)}]) }, [{"tx_hash", Option(Hash)},
{"tx", Option(Tx)} ]) },
%% Strings %% Strings
StringScope = #scope StringScope = #scope
@ -584,6 +622,7 @@ global_env() ->
{"is_contract", Fun1(Address, Bool)}, {"is_contract", Fun1(Address, Bool)},
{"is_payable", Fun1(Address, Bool)}]) }, {"is_payable", Fun1(Address, Bool)}]) },
#env{ scopes = #env{ scopes =
#{ [] => TopScope #{ [] => TopScope
, ["Chain"] => ChainScope , ["Chain"] => ChainScope
@ -601,6 +640,9 @@ global_env() ->
, ["Int"] => IntScope , ["Int"] => IntScope
, ["Address"] => AddressScope , ["Address"] => AddressScope
} }
, fields =
maps:from_list([{N, [#field_info{ ann = [], field_t = T, record_t = Tx, kind = record }]}
|| {N, T} <- TxFlds ])
}. }.

View File

@ -178,6 +178,7 @@ ast_to_fcode(Code, Options) ->
-spec init_env([option()]) -> env(). -spec init_env([option()]) -> env().
init_env(Options) -> init_env(Options) ->
ChainTxArities = [3, 0, 0, 0, 0, 0, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
#{ type_env => init_type_env(), #{ type_env => init_type_env(),
fun_env => #{}, fun_env => #{},
builtins => builtins(), builtins => builtins(),
@ -189,7 +190,31 @@ init_env(Options) ->
["AENS", "OraclePt"] => #con_tag{ tag = 1, arities = [1, 1, 1, 1] }, ["AENS", "OraclePt"] => #con_tag{ tag = 1, arities = [1, 1, 1, 1] },
["AENS", "ContractPt"] => #con_tag{ tag = 2, arities = [1, 1, 1, 1] }, ["AENS", "ContractPt"] => #con_tag{ tag = 2, arities = [1, 1, 1, 1] },
["AENS", "ChannelPt"] => #con_tag{ tag = 3, arities = [1, 1, 1, 1] }, ["AENS", "ChannelPt"] => #con_tag{ tag = 3, arities = [1, 1, 1, 1] },
["AENS", "Name"] => #con_tag{ tag = 0, arities = [3] } ["AENS", "Name"] => #con_tag{ tag = 0, arities = [3] },
["Chain", "GAMetaTx"] => #con_tag{ tag = 0, arities = [2] },
["Chain", "PayingForTx"] => #con_tag{ tag = 0, arities = [2] },
["Chain", "SpendTx"] => #con_tag{ tag = 0, arities = ChainTxArities },
["Chain", "OracleRegisterTx"] => #con_tag{ tag = 1, arities = ChainTxArities },
["Chain", "OracleQueryTx"] => #con_tag{ tag = 2, arities = ChainTxArities },
["Chain", "OracleResponseTx"] => #con_tag{ tag = 3, arities = ChainTxArities },
["Chain", "OracleExtendTx"] => #con_tag{ tag = 4, arities = ChainTxArities },
["Chain", "NamePreclaimTx"] => #con_tag{ tag = 5, arities = ChainTxArities },
["Chain", "NameClaimTx"] => #con_tag{ tag = 6, arities = ChainTxArities },
["Chain", "NameUpdateTx"] => #con_tag{ tag = 7, arities = ChainTxArities },
["Chain", "NameRevokeTx"] => #con_tag{ tag = 8, arities = ChainTxArities },
["Chain", "NameTransferTx"] => #con_tag{ tag = 9, arities = ChainTxArities },
["Chain", "ChannelCreateTx"] => #con_tag{ tag = 10, arities = ChainTxArities },
["Chain", "ChannelDepositTx"] => #con_tag{ tag = 11, arities = ChainTxArities },
["Chain", "ChannelWithdrawTx"] => #con_tag{ tag = 12, arities = ChainTxArities },
["Chain", "ChannelForceProgressTx"] => #con_tag{ tag = 13, arities = ChainTxArities },
["Chain", "ChannelCloseMutualTx"] => #con_tag{ tag = 14, arities = ChainTxArities },
["Chain", "ChannelCloseSoloTx"] => #con_tag{ tag = 15, arities = ChainTxArities },
["Chain", "ChannelSlashTx"] => #con_tag{ tag = 16, arities = ChainTxArities },
["Chain", "ChannelSettleTx"] => #con_tag{ tag = 17, arities = ChainTxArities },
["Chain", "ChannelSnapshotSoloTx"] => #con_tag{ tag = 18, arities = ChainTxArities },
["Chain", "ContractCreateTx"] => #con_tag{ tag = 19, arities = ChainTxArities },
["Chain", "ContractCallTx"] => #con_tag{ tag = 20, arities = ChainTxArities },
["Chain", "GAAttachTx"] => #con_tag{ tag = 21, arities = ChainTxArities }
}, },
options => Options, options => Options,
functions => #{} }. functions => #{} }.
@ -221,7 +246,7 @@ builtins() ->
{"gt_inv", 1}, {"gt_add", 2}, {"gt_mul", 2}, {"gt_pow", 2}, {"gt_is_one", 1}, {"gt_inv", 1}, {"gt_add", 2}, {"gt_mul", 2}, {"gt_pow", 2}, {"gt_is_one", 1},
{"pairing", 2}, {"miller_loop", 2}, {"final_exp", 1}, {"pairing", 2}, {"miller_loop", 2}, {"final_exp", 1},
{"int_to_fr", 1}, {"int_to_fp", 1}, {"fr_to_int", 1}, {"fp_to_int", 1}]}, {"int_to_fr", 1}, {"int_to_fp", 1}, {"fr_to_int", 1}, {"fp_to_int", 1}]},
{["Auth"], [{"tx_hash", none}]}, {["Auth"], [{"tx_hash", none}, {"tx", none}]},
{["String"], [{"length", 1}, {"concat", 2}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]}, {["String"], [{"length", 1}, {"concat", 2}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2}, {["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]}, {"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
@ -241,6 +266,11 @@ state_layout(Env) -> maps:get(state_layout, Env, {reg, 1}).
-spec init_type_env() -> type_env(). -spec init_type_env() -> type_env().
init_type_env() -> init_type_env() ->
BaseTx = {variant, [[address, integer, string], [], [], [], [], [], [string],
[hash], [hash], [address, hash], [address],
[address, integer], [address, integer], [address],
[address], [address], [address], [address], [address],
[integer], [address, integer], []]},
#{ ["int"] => ?type(integer), #{ ["int"] => ?type(integer),
["bool"] => ?type(boolean), ["bool"] => ?type(boolean),
["bits"] => ?type(bits), ["bits"] => ?type(bits),
@ -257,6 +287,9 @@ init_type_env() ->
["Chain", "ttl"] => ?type({variant, [[integer], [integer]]}), ["Chain", "ttl"] => ?type({variant, [[integer], [integer]]}),
["AENS", "pointee"] => ?type({variant, [[address], [address], [address], [address]]}), ["AENS", "pointee"] => ?type({variant, [[address], [address], [address], [address]]}),
["AENS", "name"] => ?type({variant, [[address, {variant, [[integer], [integer]]}, {map, string, {variant, [[address], [address], [address], [address]]}}]]}), ["AENS", "name"] => ?type({variant, [[address, {variant, [[integer], [integer]]}, {map, string, {variant, [[address], [address], [address], [address]]}}]]}),
["Chain", "ga_meta_tx"] => ?type({variant, [[address, integer]]}),
["Chain", "paying_for_tx"] => ?type({variant, [[address, integer]]}),
["Chain", "base_tx"] => ?type(BaseTx),
["MCL_BLS12_381", "fr"] => ?type({bytes, 32}), ["MCL_BLS12_381", "fr"] => ?type({bytes, 32}),
["MCL_BLS12_381", "fp"] => ?type({bytes, 48}) ["MCL_BLS12_381", "fp"] => ?type({bytes, 48})
}. }.

View File

@ -544,7 +544,9 @@ builtin_to_scode(Env, aens_update, [_Sign, _Account, _NameString, _TTL, _ClientT
builtin_to_scode(Env, aens_lookup, [_Name] = Args) -> builtin_to_scode(Env, aens_lookup, [_Name] = Args) ->
call_to_scode(Env, aeb_fate_ops:aens_lookup(?a, ?a), Args); call_to_scode(Env, aeb_fate_ops:aens_lookup(?a, ?a), Args);
builtin_to_scode(_Env, auth_tx_hash, []) -> builtin_to_scode(_Env, auth_tx_hash, []) ->
[aeb_fate_ops:auth_tx_hash(?a)]. [aeb_fate_ops:auth_tx_hash(?a)];
builtin_to_scode(_Env, auth_tx, []) ->
[aeb_fate_ops:auth_tx(?a)].
%% -- Operators -- %% -- Operators --
@ -846,6 +848,7 @@ attributes(I) ->
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]); {'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
{'ADDRESS_TO_CONTRACT', A, B} -> Pure(A, [B]); {'ADDRESS_TO_CONTRACT', A, B} -> Pure(A, [B]);
{'AUTH_TX_HASH', A} -> Pure(A, []); {'AUTH_TX_HASH', A} -> Pure(A, []);
{'AUTH_TX', A} -> Pure(A, []);
{'BYTES_TO_INT', A, B} -> Pure(A, [B]); {'BYTES_TO_INT', A, B} -> Pure(A, [B]);
{'BYTES_TO_STR', A, B} -> Pure(A, [B]); {'BYTES_TO_STR', A, B} -> Pure(A, [B]);
{'BYTES_CONCAT', A, B, C} -> Pure(A, [B, C]); {'BYTES_CONCAT', A, B, C} -> Pure(A, [B, C]);

View File

@ -146,6 +146,7 @@ compilable_contracts() ->
"events", "events",
"include", "include",
"basic_auth", "basic_auth",
"basic_auth_tx",
"bitcoin_auth", "bitcoin_auth",
"address_literals", "address_literals",
"bytes_equality", "bytes_equality",
@ -171,7 +172,7 @@ compilable_contracts() ->
]. ].
not_yet_compilable(fate) -> []; not_yet_compilable(fate) -> [];
not_yet_compilable(aevm) -> ["pairing_crypto", "aens_update"]. not_yet_compilable(aevm) -> ["pairing_crypto", "aens_update", "basic_auth_tx"].
%% Contracts that should produce type errors %% Contracts that should produce type errors

View File

@ -0,0 +1,74 @@
// namespace Chain =
// record tx = { paying_for : option(Chain.paying_for_tx)
// , ga_metas : list(Chain.ga_meta_tx)
// , actor : address
// , fee : int
// , ttl : int
// , tx : Chain.base_tx }
// datatype ga_meta_tx = GAMetaTx(address, int)
// datatype paying_for_tx = PayingForTx(address, int)
// datatype base_tx = SpendTx(address, int, string)
// | OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
// | NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
// | NameRevokeTx(hash) | NameTransferTx(address, string)
// | ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
// | ChannelForceProgressTx(address) | ChannelCloseMutualTx(address) | ChannelCloseSoloTx(address)
// | ChannelSlashTx(address) | ChannelSettleTx(address) | ChannelSnapshotSoloTx(address)
// | ContractCreateTx(int) | ContractCallTx(address, int)
// | GAAttachTx
// Contract replicating "normal" Aeternity authentication
contract BasicAuthTx =
record state = { nonce : int, owner : address }
datatype foo = Bar | Baz()
entrypoint init() = { nonce = 1, owner = Call.caller }
stateful entrypoint authorize(n : int, s : signature) : bool =
require(n >= state.nonce, "Nonce too low")
require(n =< state.nonce, "Nonce too high")
put(state{ nonce = n + 1 })
switch(Auth.tx_hash)
None => abort("Not in Auth context")
Some(tx_hash) =>
let Some(tx0) = Auth.tx
let x : option(Chain.paying_for_tx) = tx0.paying_for
let x : list(Chain.ga_meta_tx) = tx0.ga_metas
let x : int = tx0.fee + tx0.ttl
let x : address = tx0.actor
let x : Chain.tx = { tx = Chain.NamePreclaimTx, paying_for = None, ga_metas = [],
fee = 123, ttl = 0, actor = Call.caller }
switch(tx0.tx)
Chain.SpendTx(receiver, amount, payload) => verify(tx_hash, n, s)
Chain.OracleRegisterTx => false
Chain.OracleQueryTx => false
Chain.OracleResponseTx => false
Chain.OracleExtendTx => false
Chain.NamePreclaimTx => false
Chain.NameClaimTx(name) => false
Chain.NameUpdateTx(name) => false
Chain.NameRevokeTx(name) => false
Chain.NameTransferTx(to, name) => false
Chain.ChannelCreateTx(other_party) => false
Chain.ChannelDepositTx(channel, amount) => false
Chain.ChannelWithdrawTx(channel, amount) => false
Chain.ChannelForceProgressTx(channel) => false
Chain.ChannelCloseMutualTx(channel) => false
Chain.ChannelCloseSoloTx(channel) => false
Chain.ChannelSlashTx(channel) => false
Chain.ChannelSettleTx(channel) => false
Chain.ChannelSnapshotSoloTx(channel) => false
Chain.ContractCreateTx(amount) => false
Chain.ContractCallTx(ct_address, amount) => false
Chain.GAAttachTx => false
function verify(tx_hash, n, s) =
Crypto.verify_sig(to_sign(tx_hash, n), state.owner, s)
entrypoint to_sign(h : hash, n : int) =
Crypto.blake2b((h, n))
entrypoint weird_string() : string =
"\x19Weird String\x42\nMore\n"