Compare commits
8 Commits
v0.9.1
...
fcf85077b2
| Author | SHA1 | Date | |
|---|---|---|---|
| fcf85077b2 | |||
| 4530fd2e93 | |||
| 2a7079129f | |||
| 88aeb39d4a | |||
| f0f86ed36d | |||
| ed252b4c06 | |||
| 5dcc05d56a | |||
| 2eca3a5338 |
+11
-3
@@ -788,9 +788,9 @@ contract_code(ID) ->
|
|||||||
Result :: {ok, Source}
|
Result :: {ok, Source}
|
||||||
| {project, Bundle}
|
| {project, Bundle}
|
||||||
| {error, Reason},
|
| {error, Reason},
|
||||||
Source :: string(),
|
Source :: binary(),
|
||||||
Bundle :: [{FilePath :: string(), Contents :: binary()}],
|
Bundle :: [{FilePath :: string(), Contents :: binary()}],
|
||||||
Reason :: chain_error() | string().
|
Reason :: chain_error() | string().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Retrieve the code of a contract as represented on chain.
|
%% Retrieve the code of a contract as represented on chain.
|
||||||
|
|
||||||
@@ -809,6 +809,8 @@ extract(Blobby) ->
|
|||||||
|
|
||||||
extract2(TarBaby) ->
|
extract2(TarBaby) ->
|
||||||
case erl_tar:extract({binary, TarBaby}, [memory, compressed]) of
|
case erl_tar:extract({binary, TarBaby}, [memory, compressed]) of
|
||||||
|
{ok, [{_, Source}]} ->
|
||||||
|
{ok, Source};
|
||||||
{ok, Bundle} ->
|
{ok, Bundle} ->
|
||||||
{project, Bundle};
|
{project, Bundle};
|
||||||
Error ->
|
Error ->
|
||||||
@@ -895,6 +897,12 @@ request(Path) ->
|
|||||||
hz_man:request(unicode:characters_to_list(Path)).
|
hz_man:request(unicode:characters_to_list(Path)).
|
||||||
|
|
||||||
|
|
||||||
|
-spec request(Path, Payload) -> {ok, Value} | {error, Reason}
|
||||||
|
when Path :: unicode:charlist(),
|
||||||
|
Payload :: unicode:charlist(),
|
||||||
|
Value :: map(),
|
||||||
|
Reason :: hz:chain_error().
|
||||||
|
|
||||||
request(Path, Payload) ->
|
request(Path, Payload) ->
|
||||||
hz_man:request(unicode:characters_to_list(Path), Payload).
|
hz_man:request(unicode:characters_to_list(Path), Payload).
|
||||||
|
|
||||||
@@ -930,7 +938,7 @@ contract_create(CreatorID, Path, InitArgs) ->
|
|||||||
Gas = 500000,
|
Gas = 500000,
|
||||||
GasPrice = min_gas_price(),
|
GasPrice = min_gas_price(),
|
||||||
contract_create(CreatorID, Nonce,
|
contract_create(CreatorID, Nonce,
|
||||||
Amount, TTL, Gas, GasPrice,
|
Gas, GasPrice, Amount, TTL,
|
||||||
Path, InitArgs);
|
Path, InitArgs);
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
|
|||||||
+60
-9
@@ -796,6 +796,10 @@ coerce_map_to_record(O, N, MemberTypes, Map) ->
|
|||||||
case zip_record_fields(MemberTypes, Map) of
|
case zip_record_fields(MemberTypes, Map) of
|
||||||
{ok, Zipped} ->
|
{ok, Zipped} ->
|
||||||
case coerce_zipped_bindings(Zipped, to_fate, field) of
|
case coerce_zipped_bindings(Zipped, to_fate, field) of
|
||||||
|
{ok, [SingleElem]} ->
|
||||||
|
% Singleton records aren't implemented as FATE tuples at
|
||||||
|
% all.
|
||||||
|
{ok, SingleElem};
|
||||||
{ok, Converted} ->
|
{ok, Converted} ->
|
||||||
{ok, {tuple, list_to_tuple(Converted)}};
|
{ok, {tuple, list_to_tuple(Converted)}};
|
||||||
Errors ->
|
Errors ->
|
||||||
@@ -821,10 +825,18 @@ coerce_record_to_map(O, N, MemberTypes, Tuple) ->
|
|||||||
single_error({record_too_few_terms, O, N, Tuple});
|
single_error({record_too_few_terms, O, N, Tuple});
|
||||||
{error, too_many_terms} ->
|
{error, too_many_terms} ->
|
||||||
single_error({record_too_many_terms, O, N, Tuple});
|
single_error({record_too_many_terms, O, N, Tuple});
|
||||||
Errors ->
|
{error, Errors} ->
|
||||||
Errors
|
correct_record_error_paths(Names, Errors)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
correct_record_error_paths(Names, Errors) ->
|
||||||
|
CorrectOne = fun({Error, [{record_element, N} | Path]}) ->
|
||||||
|
FieldName = lists:nth(N + 1, Names),
|
||||||
|
{Error, [{record_element, N, FieldName} | Path]}
|
||||||
|
end,
|
||||||
|
Corrected = lists:map(CorrectOne, Errors),
|
||||||
|
{error, Corrected}.
|
||||||
|
|
||||||
zip_record_fields(Fields, Map) ->
|
zip_record_fields(Fields, Map) ->
|
||||||
case lists:mapfoldl(fun zip_record_field/2, {Map, []}, Fields) of
|
case lists:mapfoldl(fun zip_record_field/2, {Map, []}, Fields) of
|
||||||
{_, {_, Missing = [_|_]}} ->
|
{_, {_, Missing = [_|_]}} ->
|
||||||
@@ -915,6 +927,11 @@ fate_to_erlang({O, N, {variant, Variants}}, {variant, _, Tag, Tuple}) ->
|
|||||||
Terms = tuple_to_list(Tuple),
|
Terms = tuple_to_list(Tuple),
|
||||||
{Name, TermTypes} = lists:nth(Tag + 1, Variants),
|
{Name, TermTypes} = lists:nth(Tag + 1, Variants),
|
||||||
coerce_variant2(O, N, Variants, Name, Tag, TermTypes, Terms, from_fate);
|
coerce_variant2(O, N, Variants, Name, Tag, TermTypes, Terms, from_fate);
|
||||||
|
fate_to_erlang({O, N, {record, [SingleMemberType]}}, Data) ->
|
||||||
|
% Singleton records aren't implemented as FATE tuples at all.
|
||||||
|
% Pretend they are, so we can get the full error indexing of the
|
||||||
|
% non-singletone case.
|
||||||
|
coerce_record_to_map(O, N, [SingleMemberType], {Data});
|
||||||
fate_to_erlang({O, N, {record, MemberTypes}}, {tuple, Tuple}) ->
|
fate_to_erlang({O, N, {record, MemberTypes}}, {tuple, Tuple}) ->
|
||||||
coerce_record_to_map(O, N, MemberTypes, Tuple);
|
coerce_record_to_map(O, N, MemberTypes, Tuple);
|
||||||
fate_to_erlang({O, N, {unknown_type, _}}, Data) ->
|
fate_to_erlang({O, N, {unknown_type, _}}, Data) ->
|
||||||
@@ -927,15 +944,30 @@ fate_to_erlang({O, N, {unknown_type, _}}, Data) ->
|
|||||||
io:format(Message, [O, N, Data])
|
io:format(Message, [O, N, Data])
|
||||||
end,
|
end,
|
||||||
{ok, Data};
|
{ok, Data};
|
||||||
fate_to_erlang({O, N, _}, Data) ->
|
fate_to_erlang(Type, Data) ->
|
||||||
case N of
|
TypeStr = type_to_iolist(Type),
|
||||||
already_normalized ->
|
io:format("Warning: Could not coerce term into ~s. Using term as is: ~p~n", [TypeStr, Data]),
|
||||||
io:format("Warning: Unimplemented type ~p.~nUsing term as is:~n~p~n", [O, Data]);
|
|
||||||
_ ->
|
|
||||||
io:format("Warning: Unimplemented type ~p (i.e. ~p).~nUsing term as is:~n~p~n", [O, N, Data])
|
|
||||||
end,
|
|
||||||
{ok, Data}.
|
{ok, Data}.
|
||||||
|
|
||||||
|
type_to_iolist({O, already_normalized, S}) ->
|
||||||
|
% Already normalized. Example output:
|
||||||
|
% type {map, [string, integer]}
|
||||||
|
opaque_type_to_iolist(O, S);
|
||||||
|
type_to_iolist({O, N, S}) ->
|
||||||
|
% Type alias. Print the alias, and then print the normalized version in
|
||||||
|
% parentheses. Example output:
|
||||||
|
% type "my_alias" (i.e. record type {"my_record_type", [integer]})
|
||||||
|
io_lib:format("type ~p (i.e. ~s)", [O, opaque_type_to_iolist(N, S)]).
|
||||||
|
|
||||||
|
opaque_type_to_iolist(N, {record, _}) ->
|
||||||
|
% N is the name of a record definition.
|
||||||
|
io_lib:format("record type ~p", [N]);
|
||||||
|
opaque_type_to_iolist(N, {variant, _}) ->
|
||||||
|
% N is the name of a variant definition.
|
||||||
|
io_lib:format("variant type ~p", [N]);
|
||||||
|
opaque_type_to_iolist(N, _) ->
|
||||||
|
% N is some other constructive type.
|
||||||
|
io_lib:format("type ~p", [N]).
|
||||||
|
|
||||||
|
|
||||||
%%% AACI Getters
|
%%% AACI Getters
|
||||||
@@ -1120,6 +1152,25 @@ record_substitution_test() ->
|
|||||||
{ok, {[], Output}} = get_function_signature(AACI, "f"),
|
{ok, {[], Output}} = get_function_signature(AACI, "f"),
|
||||||
check_roundtrip(Output, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
check_roundtrip(Output, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
||||||
|
|
||||||
|
singleton_record_substitution_test() ->
|
||||||
|
Contract = "
|
||||||
|
contract C =
|
||||||
|
record single('t) = { it: 't }
|
||||||
|
entrypoint f(): single(int) = { it = 1 }
|
||||||
|
entrypoint g(): single(single(int)) = { it = { it = 2 } }
|
||||||
|
entrypoint h(): single(int * int) = { it = (3, 4) }
|
||||||
|
",
|
||||||
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
|
{ok, {[], FOutput}} = get_function_signature(AACI, "f"),
|
||||||
|
check_roundtrip(FOutput, #{"it" => 123}, 123),
|
||||||
|
{ok, {[], GOutput}} = get_function_signature(AACI, "g"),
|
||||||
|
check_roundtrip(GOutput, #{"it" => #{"it" => 123}}, 123),
|
||||||
|
{ok, {[], HOutput}} = get_function_signature(AACI, "h"),
|
||||||
|
check_roundtrip(HOutput, #{"it" => {123, 456}}, {tuple, {123, 456}}),
|
||||||
|
% Also check that records have accurate paths, since the implementation for
|
||||||
|
% record error paths is a bit fiddly.
|
||||||
|
{error, [{{tuple_too_many_terms, _, _, _}, [{record_element, 0, "it"}]}]} = fate_to_erlang(HOutput, {tuple, {1, 2, 3}}).
|
||||||
|
|
||||||
tuple_substitution_test() ->
|
tuple_substitution_test() ->
|
||||||
Contract = "
|
Contract = "
|
||||||
contract C =
|
contract C =
|
||||||
|
|||||||
Reference in New Issue
Block a user