Skip to content

Commit

Permalink
Merge pull request #2735 from aeternity/PT-168256738-fix-sum-total
Browse files Browse the repository at this point in the history
Pt 168256738 fix sum total
  • Loading branch information
ThomasArts committed Sep 4, 2019
2 parents 47d74f1 + 549e792 commit 3d102bc
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 14 deletions.
13 changes: 13 additions & 0 deletions apps/aecore/src/aec_trees.erl
Original file line number Diff line number Diff line change
Expand Up @@ -289,25 +289,31 @@ set_contracts(Trees, Contracts) ->
, 'oracles' => non_neg_integer()
, 'oracle_queries' => non_neg_integer()
, 'locked' => non_neg_integer()
, 'auctions' => non_neg_integer()
}.
sum_total_coin(Trees) ->
Accounts = accounts(Trees),
Channels = channels(Trees),
Contracts = contracts(Trees),
Oracles = oracles(Trees),
Names = ns(Trees),
LockAccount = aec_governance:locked_coins_holder_account(),
AIterator = aec_accounts_trees:mtree_iterator(Accounts),
FirstAccount = aeu_mtrees:iterator_next(AIterator),
CIterator = aesc_state_tree:mtree_iterator(Channels),
FirstChannel = aeu_mtrees:iterator_next(CIterator),
ChannelAmount = sum_channels(FirstChannel, 0),
AuctionIter = aens_state_tree:auction_iterator(Names),
FirstAuction = aens_state_tree:auction_iterator_next(AuctionIter),
SumAuctions = sum_auctions(FirstAuction, 0),
Sum = #{ 'accounts' => 0
, 'channels' => ChannelAmount
, 'contracts' => 0
, 'contract_oracles' => 0
, 'oracles' => 0
, 'oracle_queries' => 0
, 'locked' => 0
, 'auctions' => SumAuctions
},
sum_accounts(FirstAccount, LockAccount, Contracts, Oracles, Sum).

Expand Down Expand Up @@ -371,6 +377,13 @@ sum_channels({ChannelPubkey, SerChannel, Iter}, Acc) ->
Acc1 = Acc + aesc_channels:channel_amount(Channel),
sum_channels(aeu_mtrees:iterator_next(Iter), Acc1).

sum_auctions('$end_of_table', Acc) ->
Acc;
sum_auctions({AuctionHash, SerAuction, Iter}, Acc) ->
Auction = aens_auctions:deserialize(AuctionHash, SerAuction),
Acc1 = Acc + aens_auctions:name_fee(Auction),
sum_auctions(aens_state_tree:auction_iterator_next(Iter), Acc1).

%%%=============================================================================
%%% Serialization for db storage
%%%=============================================================================
Expand Down
103 changes: 103 additions & 0 deletions apps/aecore/test/aec_chain_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,9 @@ token_supply_test_() ->
] ++
[{"Test sum of generalized accounts", fun token_supply_ga/0}
|| aect_test_utils:latest_protocol_version() >= ?FORTUNA_PROTOCOL_VSN
] ++
[{"Test sum of auctions", fun token_supply_auctions/0}
|| aect_test_utils:latest_protocol_version() >= ?LIMA_PROTOCOL_VSN
]
}.

Expand Down Expand Up @@ -1691,6 +1694,86 @@ token_supply_ga() ->

ok.

token_supply_auctions() ->
TestHeight = 20,
%% We don't want to care about coinbase this time.
Delay = 1000,
#{ public := PubKey1, secret := PrivKey1 } = enacl:sign_keypair(),
#{ public := PubKey2, secret := PrivKey2 } = enacl:sign_keypair(),
PresetAmount = 4000000000000000 * aec_test_utils:min_gas_price(),
PresetAccounts = [{PubKey1, PresetAmount}, {PubKey2, PresetAmount}],
Fee = 100000 * aec_test_utils:min_gas_price(),
NameFee = 400000000000000000,
Salt = 123,
Name1 = <<"expensive-name-in-auction.aet">>,
Name2 = <<"this-name-is-too-long-to-end-up-in-an-auction.aet">>,
PreclaimFun =
fun(Address, Nonce, Name) ->
make_name_preclaim_tx(Address, Nonce, Name, Salt, Fee)
end,
ClaimFun =
fun(Address, Nonce, Name, Slt, Bid) ->
make_name_claim_tx(Address, Nonce, Name, Slt, Fee, Bid)
end,
TxsFun = fun(1) -> [aec_test_utils:sign_tx(PreclaimFun(PubKey1, 1, Name1), PrivKey1)];
(2) -> [aec_test_utils:sign_tx(PreclaimFun(PubKey2, 1, Name2), PrivKey2)];
(3) -> [aec_test_utils:sign_tx(ClaimFun(PubKey1, 2, Name1, Salt, NameFee), PrivKey1)];
(4) -> [aec_test_utils:sign_tx(ClaimFun(PubKey2, 2, Name1, 0, NameFee + NameFee div 20), PrivKey2)];
(5) -> [aec_test_utils:sign_tx(ClaimFun(PubKey1, 3, Name1, 0, 2 * NameFee), PrivKey1)];
(6) -> [aec_test_utils:sign_tx(ClaimFun(PubKey2, 3, Name2, Salt, NameFee), PrivKey2)];
(_) -> []
end,
meck:expect(aec_fork_block_settings, genesis_accounts, 0, PresetAccounts),
meck:expect(aec_governance, beneficiary_reward_delay, 0, Delay),
Targets = lists:duplicate(TestHeight, ?GENESIS_TARGET),
Chain = gen_blocks_only_chain_by_target(PresetAccounts, Targets, 111, TxsFun),
ok = write_blocks_to_chain(Chain),

%% Only presets
{ok, Map1} = aec_chain:sum_tokens_at_height(1),
Total0 = PresetAmount * 2,
?assertEqual(Total0, maps:get(accounts, Map1)),
?assertEqual(0, maps:get(auctions, Map1)),

%% One preclaim done.
{ok, Map2} = aec_chain:sum_tokens_at_height(2),
Total1 = Total0 - Fee,
?assertEqual(Total1, maps:get(accounts, Map2)),
?assertEqual(0, maps:get(auctions, Map2)),

%% Second preclaim done.
{ok, Map3} = aec_chain:sum_tokens_at_height(3),
Total2 = Total1 - Fee,
?assertEqual(Total2, maps:get(accounts, Map3)),
?assertEqual(0, maps:get(auctions, Map3)),

%% first claim starts an auction
{ok, Map4} = aec_chain:sum_tokens_at_height(4),
Total3 = Total2 - Fee - NameFee,
?assertEqual(Total3, maps:get(accounts, Map4)),
?assertEqual(NameFee, maps:get(auctions, Map4)),

%% second claim
{ok, Map5} = aec_chain:sum_tokens_at_height(5),
Total4 = Total3 - Fee - NameFee div 20, %% one returned, new fee reduced
?assertEqual(Total4, maps:get(accounts, Map5)),
?assertEqual(NameFee + NameFee div 20, maps:get(auctions, Map5)),

%% third claim
{ok, Map6} = aec_chain:sum_tokens_at_height(6),
Total5 = Total4 - Fee + NameFee div 20 - NameFee, %% one returned, new fee reduced
?assertEqual(Total5, maps:get(accounts, Map6)),
?assertEqual(2*NameFee, maps:get(auctions, Map6)),

%% Second name does not end up in auction
{ok, Map7} = aec_chain:sum_tokens_at_height(7),
Total6 = Total5 - Fee - NameFee, %% one returned, new fee reduced
?assertEqual(Total6, maps:get(accounts, Map7)),
?assertEqual(2 * NameFee, maps:get(auctions, Map7)),
?assertEqual(NameFee, maps:get(locked, Map7)),

ok.

%%%===================================================================
%%% Internal functions
%%%===================================================================
Expand Down Expand Up @@ -1883,6 +1966,26 @@ make_ga_meta_tx(Pubkey, AuthData, InnerTx, Fee, Gas, GasPrice) ->
, tx => InnerTx}),
Tx.

make_name_preclaim_tx(Pubkey, Nonce, Name, Salt, Fee) ->
AccountId = aeser_id:create(account, Pubkey),
Commitment = aens_hash:commitment_hash(Name, Salt),
CommitmentId = aeser_id:create(commitment, Commitment),
{ok, Tx} = aens_preclaim_tx:new(#{account_id => AccountId,
nonce => Nonce,
commitment_id => CommitmentId,
fee => Fee}),
Tx.

make_name_claim_tx(Pubkey, Nonce, Name, Salt, Fee, Bid) ->
AccountId = aeser_id:create(account, Pubkey),
{ok, Tx} = aens_claim_tx:new(#{account_id => AccountId,
nonce => Nonce,
name => Name,
name_salt => Salt,
name_fee => Bid,
fee => Fee}),
Tx.

reward_40(Fee) -> Fee * 4 div 10.

reward_60(Fee) -> Fee - reward_40(Fee).
Expand Down
24 changes: 23 additions & 1 deletion apps/aens/src/aens_state_tree.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
lookup_name_auction/2,
lookup_name/2,
new_with_backend/2,
root_hash/1]).
root_hash/1,
auction_iterator/1,
auction_iterator_next/1]).

-export([ from_binary_without_backend/1
, to_binary_without_backend/1
Expand Down Expand Up @@ -112,6 +114,26 @@ prune(NextBlockHeight, Trees) ->
Trees1 = aec_trees:set_ns(Trees, NTree),
run_elapsed(ExpiredActions, Trees1, NextBlockHeight).

-spec auction_iterator(tree()) -> aeu_mtrees:iterator().
auction_iterator(#ns_tree{mtree = MTree}) ->
aeu_mtrees:iterator(MTree).

-spec auction_iterator_next(aeu_mtrees:iterator()) ->
{mkey(), mvalue(), aeu_mtrees:iterator()} | '$end_of_table'.
auction_iterator_next(Iter) ->
case aeu_mtrees:iterator_next(Iter) of
{Key, Value, NextIter} ->
case byte_size(Key) > 32 of
true ->
{Key, Value, NextIter};
false ->
auction_iterator_next(NextIter)
end;
'$end_of_table' ->
'$end_of_table'
end.


run_elapsed([], Trees, _) ->
Trees;
run_elapsed([{aens_names, Id, Serialized}|Expired], Trees, Height) ->
Expand Down
31 changes: 18 additions & 13 deletions apps/aeprimop/src/aeprimop.erl
Original file line number Diff line number Diff line change
Expand Up @@ -539,18 +539,21 @@ spend({From, To, Amount, Mode}, #state{} = S) when is_integer(Amount), Amount >=
%%% For Lima auctioned names, the lock fee is returned
%%% in case of overbidding

lock_amount(From, Amount, #state{height = Height} = S) ->
lock_namefee(Kind, From, Amount, #state{height = Height} = S) ->
LockFee = aec_governance:name_claim_locked_fee(),
Protocol = aec_hard_forks:protocol_effective_at_height(Height),
case Protocol >= ?LIMA_PROTOCOL_VSN of
true when Amount > 0 -> ok;
false when Amount == LockFee -> ok;
_ -> runtime_error(illegal_name_fee)
end,
{Account, S1} = get_account(From, S),
assert_account_balance(Account, Amount),
S2 = account_spend(Account, Amount, S1),
int_lock_amount(Amount, S2).
case Protocol >= ?LIMA_PROTOCOL_VSN of
true when Amount > 0, Kind == spend ->
S2;
true when Amount > 0, Kind == lock ->
int_lock_amount(Amount, S2);
false when Amount == LockFee, Kind == lock ->
int_lock_amount(Amount, S2);
_ -> runtime_error(illegal_name_fee)
end.

%%%-------------------------------------------------------------------

Expand Down Expand Up @@ -738,12 +741,15 @@ name_claim({AccountPubkey, PlainName, NameSalt, NameFee, PreclaimDelta}, S) ->
AuctionHash = aens_hash:to_auction_hash(NameHash),
%% Cannot compute CommitmentHash before we know whether in auction
Protocol = aec_hard_forks:protocol_effective_at_height(S#state.height),
BidTimeout = aec_governance:name_claim_bid_timeout(NameAscii, Protocol),
S0 = lock_namefee(if BidTimeout == 0 -> lock;
true -> spend
end, AccountPubkey, NameFee, S),
case aec_governance:name_claim_bid_timeout(NameAscii, Protocol) of
0 ->
%% No auction for this name, preclaim delta suffices
%% For clarity DeltaTTL for name computed here
DeltaTTL = aec_governance:name_claim_max_expiration(),
S0 = lock_amount(AccountPubkey, NameFee, S),
CommitmentHash = aens_hash:commitment_hash(NameAscii, NameSalt),
{Commitment, S1} = get_commitment(CommitmentHash, name_not_preclaimed, S0),
assert_claim_after_preclaim({AccountPubkey, Commitment, NameAscii, NameRegistrar, NameFee, PreclaimDelta}, S1),
Expand All @@ -752,8 +758,8 @@ name_claim({AccountPubkey, PlainName, NameSalt, NameFee, PreclaimDelta}, S) ->
put_name(Name, S2);
Timeout when NameSalt == 0 ->
%% Auction should be running, new bid comes in
assert_not_name(NameHash, S), %% just to be sure
{Auction, S1} = get_name_auction(AuctionHash, name_not_in_auction, S),
assert_not_name(NameHash, S0), %% just to be sure
{Auction, S1} = get_name_auction(AuctionHash, name_not_in_auction, S0),
PreviousBidderPubkey = aens_auctions:bidder_pubkey(Auction),
PreviousBid = aens_auctions:name_fee(Auction),
assert_name_bid_fee(NameAscii, NameFee, S#state.height), %% just in case, consensus may have changed
Expand All @@ -766,11 +772,10 @@ name_claim({AccountPubkey, PlainName, NameSalt, NameFee, PreclaimDelta}, S) ->
put_name_auction(NewAuction, S3);
Timeout when NameSalt =/= 0 ->
%% This is the first claim that starts an auction
assert_not_name_auction(AuctionHash, S),
assert_not_name_auction(AuctionHash, S0),
CommitmentHash = aens_hash:commitment_hash(NameAscii, NameSalt),
{Commitment, S1} = get_commitment(CommitmentHash, name_not_preclaimed, S),
{Commitment, S1} = get_commitment(CommitmentHash, name_not_preclaimed, S0),
assert_claim_after_preclaim({AccountPubkey, Commitment, NameAscii, NameRegistrar, NameFee, PreclaimDelta}, S1),

%% Now put this Name in Auction instead of in Names
Auction = aens_auctions:new(AuctionHash, AccountPubkey, NameFee, Timeout, S1#state.height),
S2 = delete_x(commitment, CommitmentHash, S1),
Expand Down

0 comments on commit 3d102bc

Please sign in to comment.