Check balance for lock and account transactions

parent 6ef12309
Pipeline #28982763 passed with stages
in 15 minutes and 15 seconds
......@@ -24,7 +24,9 @@
serialize/1,
unpack_binary/2,
handle_bin/2,
valid_since/1]).
required_balance/2,
valid_since/1,
value/1]).
-spec valid_since(tx()) -> block_height() | none.
valid_since(#transfer_tx{valid_since=ValidSince}) ->
......@@ -48,6 +50,16 @@ from(#vote_tx{address=Address}) ->
from(#burn_tx{address=Address}) ->
Address.
-spec value(tx()) -> non_neg_integer().
value(Tx) when is_record(Tx, burn_tx) orelse is_record(Tx, transfer_tx) ->
get_value(value, Tx);
value(_) ->
0.
-spec required_balance(tx(), data()) -> non_neg_integer().
required_balance(Tx, Data) ->
value(Tx) + ercoin_fee:total(Tx, Data).
-spec serialize(tx()) -> binary().
serialize(
#transfer_tx{
......@@ -165,8 +177,13 @@ error_code(Tx, Data=#data{height=Height, epoch_length=EpochLength}) ->
case ercoin_account:get(ercoin_tx:from(Tx), Data) of
none ->
?NOT_FOUND;
From ->
error_code_1(Tx, Data, From)
From=#account{balance=Balance} ->
case Balance >= ercoin_tx:required_balance(Tx, Data) of
true ->
error_code_1(Tx, Data, From);
false ->
?INSUFFICIENT_FUNDS
end
end
end;
_ ->
......@@ -174,7 +191,7 @@ error_code(Tx, Data=#data{height=Height, epoch_length=EpochLength}) ->
end.
-spec error_code_1(tx(), data(), account() | none) -> error_code().
error_code_1(Tx=#transfer_tx{to=To, value=Value}, Data, #account{locked_until=LockedUntil, balance=Balance}) ->
error_code_1(Tx=#transfer_tx{to=To}, Data, #account{locked_until=LockedUntil}) ->
case in_fresh_txs(Tx, Data) of
false ->
case ercoin_account:get(To, Data) of
......@@ -183,12 +200,7 @@ error_code_1(Tx=#transfer_tx{to=To, value=Value}, Data, #account{locked_until=Lo
#account{} ->
case LockedUntil of
none ->
case Balance < ercoin_fee:total(Tx, Data) + Value of
false ->
?OK;
true ->
?INSUFFICIENT_FUNDS
end;
?OK;
_ ->
?FORBIDDEN
end
......@@ -245,17 +257,12 @@ error_code_1(Tx=#vote_tx{address=Address}, Data=#data{validators=Validators, fut
_ ->
?ALREADY_EXECUTED
end;
error_code_1(Tx=#burn_tx{value=Value}, Data, #account{balance=Balance, locked_until=LockedUntil}) ->
error_code_1(Tx=#burn_tx{}, Data, #account{locked_until=LockedUntil}) ->
case in_fresh_txs(Tx, Data) of
false ->
case LockedUntil of
none ->
case Balance < ercoin_fee:total(Tx, Data) + Value of
false ->
?OK;
true ->
?INSUFFICIENT_FUNDS
end;
?OK;
_ ->
?FORBIDDEN
end;
......
......@@ -164,17 +164,7 @@ data_sks_and_lock_tx() ->
-spec make_sufficient_balance(data(), tx()) -> data().
make_sufficient_balance(Data, Tx) ->
Account = ercoin_account:get(ercoin_tx:from(Tx), Data),
Fee = ercoin_fee:total(Tx, Data),
MinBalance =
case Tx of
#transfer_tx{value=Value} ->
Fee + Value;
#burn_tx{value=Value} ->
Fee + Value;
_ ->
Fee
end,
NewAccount = Account#account{balance=max(MinBalance, Account#account.balance)},
NewAccount = Account#account{balance=max(ercoin_tx:required_balance(Tx, Data), Account#account.balance)},
ercoin_account:put(NewAccount, Data).
transfer_tx({Data, SKs}, From, To) ->
......@@ -292,20 +282,20 @@ data_with_invalid_tx_bin() ->
TxBin = ercoin_tx:serialize(Tx),
{Data, <<Prefix/binary, TxBin/binary, Suffix/binary>>}
end),
%% Insufficient balance for transfer/burn.
%% Insufficient balance.
?LET(
{{{Data, SKs}, Tx},
{{{Data, _}, Tx},
LackingFunds},
{oneof(
[fun data_sks_and_transfer_tx/0,
fun data_sks_and_burn_tx/0]),
{?SUCHTHAT(
{_, Tx},
data_sks_and_tx(),
not is_record(Tx, vote_tx)),
pos_integer()},
begin
Account = ercoin_account:get(ercoin_tx:from(Tx), Data),
InvalidValue = max(0, Account#account.balance - ercoin_fee:total(Tx, Data) + LackingFunds),
InvalidTx =
sign_tx(set_value(value, InvalidValue, Tx), SKs),
{Data, ercoin_tx:serialize(InvalidTx)}
InvalidAccount = Account#account{balance=max(0, ercoin_tx:required_balance(Tx, Data) - LackingFunds)},
{ercoin_account:put(InvalidAccount, Data),
ercoin_tx:serialize(Tx)}
end),
%% Bad signature.
?LET(
......
......@@ -163,3 +163,9 @@ prop_non_burn_tx_does_not_change_money_supply() ->
?IMPLIES(
not is_record(Tx, burn_tx),
ercoin_data:money_supply(ercoin_tx:apply(Tx, Data)) =:= ercoin_data:money_supply(Data))).
prop_tx_does_not_increase_money_supply() ->
?FORALL(
{Data, Tx},
data_with_tx(),
ercoin_data:money_supply(ercoin_tx:apply(Tx, Data)) =< ercoin_data:money_supply(Data)).
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment