Skip to content

Commit

Permalink
fail gracefully on signed tx in /dry-run (#4287)
Browse files Browse the repository at this point in the history
* Reproduce error 500 when sending signed Tx to dry-run

* Dry run should respond with 400 when Tx is signed

* Update apps/aehttp/src/aehttp_helpers.erl

Co-authored-by: Hans Svensson <hanssv@gmail.com>

---------

Co-authored-by: Hans Svensson <hanssv@gmail.com>
  • Loading branch information
ThomasArts and hanssv committed Mar 7, 2024
1 parent 37a228b commit 8a376be
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 11 deletions.
2 changes: 1 addition & 1 deletion apps/aehttp/priv/oas3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ paths:
- external
- dry-run
operationId: ProtectedDryRunTxs
description: Dry-run transactions on top of a given block. Supports all TXs except GAMetaTx, PayingForTx and OffchainTx. The maximum gas limit of all calls is capped. The maximum gas limit per request is a global node setting. Since DryRunCallReq object do not have a mandatory gas field, if not set a default value of 1000000 is being used instead.
description: Dry-run unsigned transactions on top of a given block. Supports all TXs except GAMetaTx, PayingForTx and OffchainTx. The maximum gas limit of all calls is capped. The maximum gas limit per request is a global node setting. Since DryRunCallReq object do not have a mandatory gas field, if not set a default value of 1000000 is being used instead.
parameters:
- $ref: '#/components/parameters/intAsString'
requestBody:
Expand Down
10 changes: 5 additions & 5 deletions apps/aehttp/src/aehttp_dispatch_ext.erl
Original file line number Diff line number Diff line change
Expand Up @@ -846,11 +846,11 @@ handle_request_('ProtectedDryRunTxs', #{ 'DryRunInput' := Req }, _Context) ->
TxGasLimit= lists:sum(
lists:map(
fun(#{<<"tx">> := ETx}) ->
case aeser_api_encoder:safe_decode(transaction, ETx) of
{ok, DTx} ->
Tx = aetx:deserialize_from_binary(DTx),
aetx:gas_limit(Tx, Height, Protocol);
{error, _Err} -> 0 %% this is handled later on
try {ok, DTx} = aeser_api_encoder:safe_decode(transaction, ETx),
Tx = aetx:deserialize_from_binary(DTx),
aetx:gas_limit(Tx, Height, Protocol)
catch _:_ ->
0 %% this is handled later on
end;
(#{<<"call_req">> := CallReq}) ->
maps:get(<<"gas">>, CallReq, ?DEFAULT_CALL_REQ_GAS_LIMIT)
Expand Down
18 changes: 14 additions & 4 deletions apps/aehttp/src/aehttp_helpers.erl
Original file line number Diff line number Diff line change
Expand Up @@ -710,19 +710,29 @@ dry_run_accounts_([Account | Accounts], Acc) ->
dry_run_txs_([], Txs) ->
{ok, lists:reverse(Txs)};
dry_run_txs_([#{ <<"tx">> := ETx } | Txs], Acc) ->
try dry_run_tx(ETx) of
{ok, Tx} -> dry_run_txs_(Txs, [{tx, Tx} | Acc]);
Err = {error, _Reason} ->
Err
catch
_:_ -> {error, "malformed transaction"}
end;
dry_run_txs_([#{ <<"call_req">> := CallReq } | Txs], Acc) ->
dry_run_txs_(Txs, [{call_req, CallReq} | Acc]).

dry_run_tx(ETx) ->
case aeser_api_encoder:safe_decode(transaction, ETx) of
{ok, DTx} ->
Tx = aetx:deserialize_from_binary(DTx),
{Type, _} = aetx:specialize_type(Tx),
case not lists:member(Type, [paying_for_tx, offchain_tx, ga_meta_tx]) of
true -> dry_run_txs_(Txs, [{tx, Tx} | Acc]);
true -> {ok, Tx};
false -> {error, lists:concat(["Unsupported transaction type ", Type])}
end;
Err = {error, _Reason} ->
Err
end;
dry_run_txs_([#{ <<"call_req">> := CallReq } | Txs], Acc) ->
dry_run_txs_(Txs, [{call_req, CallReq} | Acc]).
end.



dry_run_results({Rs, Events}) ->
Expand Down
9 changes: 8 additions & 1 deletion apps/aehttp/test/aehttp_dryrun_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,11 @@ spend_txs(Config) ->

#{ public := EPub } = enacl:sign_keypair(),

Tx1 = {tx, create_spend_tx(APub, EPub, 100000 * aec_test_utils:min_gas_price(), 20000 * aec_test_utils:min_gas_price(), 1, 100)},
SpendTx1 = create_spend_tx(APub, EPub, 100000 * aec_test_utils:min_gas_price(), 20000 * aec_test_utils:min_gas_price(), 1, 100),
Tx1 = {tx, SpendTx1},
Tx2 = {tx, create_spend_tx(EPub, APub, 100, 20000 * aec_test_utils:min_gas_price(), 1, 100)},
SignedTx1 = aetx_sign:new(SpendTx1, [<<0:512>>]),
BinSignedTx1 = aeser_api_encoder:encode(transaction, aetx_sign:serialize_to_binary(SignedTx1)),

{ok, 200, #{ <<"results">> := [#{ <<"result">> := <<"ok">>,
<<"type">> := <<"spend">> },
Expand All @@ -165,6 +168,10 @@ spend_txs(Config) ->
{ok, 200, #{ <<"results">> := [#{ <<"result">> := <<"error">> }, #{ <<"result">> := <<"ok">> }] }} =
dry_run(Config, TopHash, [Tx2, Tx1]),

?assertMatch({ok, 400, #{<<"reason">> := <<"Bad request: ", _/binary>>}},
dry_run(Config, TopHash, [Tx2, Tx1, {tx, BinSignedTx1}])),


%% Negative test - badly encoded Tx
BinTx1 = aeser_api_encoder:encode(transaction, aetx:serialize_to_binary(element(2, Tx1))),
{ok, 400, #{ <<"reason">> := <<"Bad request: invalid_encoding">> }} = dry_run(Config, TopHash, [{tx, <<BinTx1/binary, 43>>}]),
Expand Down

0 comments on commit 8a376be

Please sign in to comment.