Update Tendermint to 0.23.1

Development data now uses simple entropy, as NIST Beacon doesn’t have
a stable API specification yet.
parent 4ce13fe3
Pipeline #29722196 passed with stages
in 18 minutes and 42 seconds
......@@ -14,14 +14,14 @@ PROJECT = ercoin
PROJECT_DESCRIPTION = A simple cryptocurrency using Tendermint
PROJECT_VERSION = 0.1.0
DEPS = abci_server datum dynarec enacl erlsha2 gb_merkle_trees iso8601 jiffy nist_beacon
dep_abci_server = git https://github.com/KrzysiekJ/abci_server.git 2f38de3b21dfb463ec33f54f6c08b7ce63c27f56
DEPS = abci_server datum dynarec elixir enacl erlsha2 gb_merkle_trees jiffy nist_beacon
dep_abci_server = git https://github.com/KrzysiekJ/abci_server.git v0.7.2
dep_datum = git https://github.com/fogfish/datum.git 4.3.3
dep_dynarec = git https://github.com/dieswaytoofast/dynarec.git 1f477
dep_elixir = git https://github.com/elixir-lang/elixir.git v1.7.3
dep_enacl = git https://github.com/jlouis/enacl.git f650c72b028e46dbbed35f94e33ebe1e8db5d7eb
dep_erlsha2 = git https://github.com/vinoski/erlsha2 e3434b33cfeea02609bbf877954d856d895b9e1d
dep_gb_merkle_trees = git https://github.com/KrzysiekJ/gb_merkle_trees.git 1687f8be1187cf0964e63012b175b286af69c21a
dep_iso8601 = git https://github.com/erlsci/iso8601.git 1.3.1
dep_jiffy = git https://github.com/davisp/jiffy.git 0.14.11
dep_nist_beacon = git https://gitlab.com/KrzysiekJ/nist_beacon v0.1.1
......@@ -35,6 +35,8 @@ dep_lfe = git https://github.com/rvirding/lfe 2880c8a2
dep_lfe.mk = git https://github.com/KrzysiekJ/lfe.mk 025e92038f330ae2b0cbfe170819419c70118ad8
DEP_PLUGINS = lfe.mk
NO_AUTOPATCH = elixir
# Whitespace to be used when creating files from templates.
SP = 4
......@@ -49,3 +51,13 @@ PLT_APPS = $(TEST_DEPS) eunit
deps:: $(DEPS_DIR)/lfe/ebin/clj.beam
$(DEPS_DIR)/lfe/ebin/clj.beam:
$(verbose) PATH=$(PATH):$(DEPS_DIR)/lfe/bin lfec +debug_info -o $(DEPS_DIR)/lfe/ebin/ $(DEPS_DIR)/lfe/src/clj.lfe
ebin/$(PROJECT).app:: no-bad-mix-app-files | $(DEPS_DIR)/elixir/ebin
$(DEPS_DIR)/elixir/ebin:
$(gen_verbose) ln -s lib/elixir/ebin deps/elixir/
no-bad-mix-app-files:
$(verbose) rm -rf $(DEPS_DIR)/elixir/lib/mix/test
.PHONY: no-bad-mix-app-files
......@@ -18,7 +18,7 @@ For support and other ephemeral discussions, see [the #ercoin IRC channel on irc
## Development installation
1. Install [Tendermint](https://tendermint.com) (version 0.21.0).
1. Install [Tendermint](https://tendermint.com) (version 0.23.1).
2. Install [Erlang](https://www.erlang.org) (19 is the minimum version).
3. Install [libsodium](https://libsodium.org) (when using a package manager, you may need to install a separate package containing development files).
4. Clone the Ercoin’s repository and enter the created directory.
......@@ -41,7 +41,7 @@ If you want to create a custom initial state, functions exported from the `ercoi
To run the project using [Docker Compose](https://docs.docker.com/compose/):
1. `docker-compose build`
2. `docker run -it --rm -v ercoin_home:/tendermint tendermint/tendermint:0.21.0 init`
2. `docker run -it --rm -v ercoin_home:/tendermint tendermint/tendermint:0.23.1 init`
3. `docker run -it --rm -e ERCOIN_HOME=/ercoin -v ercoin_home:/ercoin ercoin_abci-server:latest /app/dev/bootstrap.sh`
4. `docker-compose up`
......
{
"genesis_time": "0001-01-01T00:00:00Z",
"chain_id": "ercoin-test",
"validators": [
{
"pub_key": {
"type": "AC26791624DE60",
"value": "4PGY0n9yUK/9dw5NBSrtkjPqVxNP2Y4kzyFzSXqoovM="
},
"power": 20,
"name": ""
}
],
"app_hash": "",
"app_state": "g1AAAAIpeNrL4E9hYElJLElMZEz8kMiQwsBZmpeSmpaZl5qSyACCWbkMDAwKDARABlMiUwYLWOmDjzMu1RcFrP9bzufLqvV2kvGrcGH/m30q5xWLPatWLPoMViTKlS4tYBKywfaFtsoE9lNnBGrDy5QObWVV5ykTKejScs1gBiuzWvToW/lzRXuPdzulLtcfZT77xtHww9+5DAtbvr2bO+OAH0gRDwNj2wIgLe5R9oIBrKv6Oqvvj5hltpLqBtquP7iebjzp02Z9+eCDQLZJbEsTXTdBDSfGoQZQw0GAEcQmyneuZ5irP3bfS1BzXrRiimHwCTOmVl2Lmadqrhd2Xq2NdcrLYEph4EstSs7PzItPzSspyi+oTGEQKErNyUxMykmFCQHDlJEEpyo6oEYJIzrNCDbqr5hOZ1lv3bLAjyY/Ej6vXL/xsJhUkNLK5c/1jC6n9cUpIqcAZDYAe7q8Pw=="
"app_hash" : "",
"app_state" : "g1AAAAIneNrL4E9hYElJLElMZEz8kMiQwsBZmpeSmpaZl5qSyACCWbkMDAwKDARABlMiUwYLWOmDjzMu1RcFrP9bzufLqvV2kvGrcGH/m30q5xWLPatWLPoMViTKlS4tYBKywfaFtsoE9lNnBGrDy5QObWVV5ykTKejScs1gBiuzWvToW/lzRXuPdzulLtcfZT77xtHww9+5DAtbvr2bO+OAH0gRDwNj2wIgLe5R9oIBrKv6Oqvvj5hltpLqBtquP7iebjzp02Z9+eCDQLZJbEsTXTdBDSfGoQZQw0GAEcQmyneuZ5irP3bfS1BzXrRiimHwCTOmVl2Lmadqrhd2Xq2NdcrLYEph4EstSs7PzItPzSspyi+oBAoUZ+YW5KTCBIAhykiCQxVFUCOEEZ1mBBu1ziTpr0y97e8MzxdhG5zvfEnxWyKefH6itJCwx/9wr5y/yPGPzAYAzZ265Q==",
"genesis_time" : "2018-09-03T18:55:36Z",
"chain_id" : "ercoin-test",
"validators" : [
{
"power" : "20",
"name" : "",
"pub_key" : {
"type" : "tendermint/PubKeyEd25519",
"value" : "4PGY0n9yUK/9dw5NBSrtkjPqVxNP2Y4kzyFzSXqoovM="
}
}
]
}
{
"address": "146DA449F1259751B2F6D69504D966E98A55F6A6",
"pub_key": {
"type": "AC26791624DE60",
"value": "4PGY0n9yUK/9dw5NBSrtkjPqVxNP2Y4kzyFzSXqoovM="
},
"last_height": 0,
"last_round": 0,
"last_height": "0",
"last_round": "0",
"last_step": 0,
"priv_key": {
"type": "954568A3288910",
"type": "tendermint/PrivKeyEd25519",
"value": "skYZ9XopqNOx61WeNzTPkgMTz9bdBETQ60il9Efq9fng8ZjSf3JQr/13Dk0FKu2SM+pXE0/ZjiTPIXNJeqii8w=="
}
}
......@@ -9,7 +9,7 @@ services:
volumes:
- ercoin_home:/ercoin
tendermint:
image: tendermint/tendermint:0.21.0
image: tendermint/tendermint:0.23.1
ports:
- "26656:26656"
- "26657:26657"
......
......@@ -5,11 +5,11 @@
-import(
ercoin_gen,
[account/0,
begin_block/1,
data/0,
data_sks/0,
data_with_account/0,
data_sks_and_account/0,
data_sks_and_account/1,
header/1,
vote/1,
vote/2]).
......@@ -55,11 +55,11 @@ init(_Args) ->
terminate(_Reason, _State, _Data) ->
ok.
handle_event({call, From}, #'RequestCheckTx'{tx=MaybeTxBin}, _, Data) ->
handle_event({call, From}, #'abci.RequestCheckTx'{tx=MaybeTxBin}, _, Data) ->
{ErrorCode, NewMempoolData} = ercoin_tx:handle_bin(MaybeTxBin, Data#data.mempool_data),
{keep_state, Data#data{mempool_data=NewMempoolData}, {reply, From, #'ResponseCheckTx'{code=ErrorCode}}};
handle_event({call, From}, #'RequestCommit'{}, committing, Data=#data{height=Height, epoch_length=EpochLength}) ->
Response = #'ResponseCommit'{data=app_hash(Data)},
{keep_state, Data#data{mempool_data=NewMempoolData}, {reply, From, #'abci.ResponseCheckTx'{code=ErrorCode}}};
handle_event({call, From}, #'abci.RequestCommit'{}, committing, Data=#data{height=Height, epoch_length=EpochLength}) ->
Response = #'abci.ResponseCommit'{data=app_hash(Data)},
Reply = {reply, From, Response},
Actions =
%% It is important that we dump data at such height that future_validators is not a promise.
......@@ -72,7 +72,7 @@ handle_event({call, From}, #'RequestCommit'{}, committing, Data=#data{height=Hei
{next_state, gossiping, Data, Actions};
handle_event(
{call, From},
#'RequestEndBlock'{},
#'abci.RequestEndBlock'{},
committing,
Data=
#data{
......@@ -113,17 +113,17 @@ handle_event(
Data3 =
remove_old_and_unlock_accounts(
Data2#data{height=NewHeight, fresh_txs=NewFreshTxs}),
{keep_state, Data3, {reply, From, #'ResponseEndBlock'{validator_updates=Diffs}}};
handle_event({call, From}, #'RequestDeliverTx'{tx=MaybeTxBin}, committing, Data)->
{keep_state, Data3, {reply, From, #'abci.ResponseEndBlock'{validator_updates=Diffs}}};
handle_event({call, From}, #'abci.RequestDeliverTx'{tx=MaybeTxBin}, committing, Data)->
{ErrorCode, NewData} = ercoin_tx:handle_bin(MaybeTxBin, Data),
{keep_state, NewData, {reply, From, #'ResponseDeliverTx'{code=ErrorCode}}};
{keep_state, NewData, {reply, From, #'abci.ResponseDeliverTx'{code=ErrorCode}}};
handle_event({call, _}, _, committing, _) ->
{keep_state_and_data, postpone};
handle_event(
{call, From},
#'RequestBeginBlock'{
validators=SigningValidators,
header=#'Header'{time=NewTimestamp}},
#'abci.RequestBeginBlock'{
last_commit_info=#'abci.LastCommitInfo'{validators=SigningValidators},
header=#'abci.Header'{time=NewTimestampProto}},
gossiping,
Data=
#data{
......@@ -142,12 +142,13 @@ handle_event(
end,
NewValidators =
lists:foldl(
fun (#'SigningValidator'{signed_last_block=Signed, validator=#'Validator'{pub_key=#'PubKey'{data=PK}}}, Acc) ->
fun (#'abci.SigningValidator'{signed_last_block=Signed, validator=#'abci.Validator'{address=TendermintAddress}}, Acc) ->
case Signed of
true ->
Acc;
false ->
<<Power, Absencies:3/unit:8, VoteBin/binary>> = gb_merkle_trees:lookup(PK, Validators),
{PK, <<Power, Absencies:3/unit:8, VoteBin/binary>>} =
ercoin_validators:key_value_by_tendermint_address(TendermintAddress, Data),
NewAbsencies = Absencies + 1,
gb_merkle_trees:enter(PK, <<Power, NewAbsencies:3/unit:8, VoteBin/binary>>, Acc)
end
......@@ -157,26 +158,26 @@ handle_event(
NewData =
Data#data{
validators=NewValidators,
timestamp=NewTimestamp,
timestamp=ercoin_timestamp:from_protobuf(NewTimestampProto),
last_epoch_end=NewLastEpochEnd},
{next_state, committing, NewData, {reply, From, #'ResponseBeginBlock'{}}};
handle_event({call, From}, Query, gossiping, Data) when is_record(Query, 'RequestQuery') ->
{next_state, committing, NewData, {reply, From, #'abci.ResponseBeginBlock'{}}};
handle_event({call, From}, Query, gossiping, Data) when is_record(Query, 'abci.RequestQuery') ->
{keep_state_and_data, {reply, From, ercoin_query:perform(Query, Data)}};
handle_event({call, From}, #'RequestInfo'{}, gossiping, Data) ->
handle_event({call, From}, #'abci.RequestInfo'{}, gossiping, Data) ->
Response =
#'ResponseInfo'{
#'abci.ResponseInfo'{
last_block_app_hash=app_hash(Data),
last_block_height=Data#data.height},
{keep_state_and_data, {reply, From, Response}};
handle_event(internal, dump_data, gossiping, Data) ->
ok = ercoin_persistence:dump_data_async(Data),
keep_state_and_data;
handle_event({call, From}, #'RequestInitChain'{app_state_bytes=AppStateJSON}, uninitialized, none) ->
handle_event({call, From}, #'abci.RequestInitChain'{app_state_bytes=AppStateJSON}, uninitialized, none) ->
Data = #data{validators=Validators} = binary_to_term(base64:decode(jiffy:decode(AppStateJSON))),
TendermintValidators = [#'Validator'{pub_key=#'PubKey'{data=PK, type="ed25519"}, power=Power} || {PK, <<Power, _/binary>>} <- gb_merkle_trees:to_orddict(Validators)],
{next_state, gossiping, Data, {reply, From, #'ResponseInitChain'{validators=TendermintValidators}}};
handle_event({call, From}, #'RequestInfo'{}, uninitialized, _) ->
Reply = #'ResponseInfo'{last_block_height=0, last_block_app_hash= <<>>},
TendermintValidators = [#'abci.Validator'{pub_key=#'abci.PubKey'{data=PK, type="ed25519"}, power=Power} || {PK, <<Power, _/binary>>} <- gb_merkle_trees:to_orddict(Validators)],
{next_state, gossiping, Data, {reply, From, #'abci.ResponseInitChain'{validators=TendermintValidators}}};
handle_event({call, From}, #'abci.RequestInfo'{}, uninitialized, _) ->
Reply = #'abci.ResponseInfo'{last_block_height=0, last_block_app_hash= <<>>},
{keep_state_and_data, {reply, From, Reply}};
handle_event(enter, _, gossiping, Data) ->
NewMempoolData = Data#data{mempool_data=undefined},
......@@ -187,7 +188,7 @@ handle_event(enter, _, _, _) ->
handle_request(Request) ->
gen_statem:call(?MODULE, Request).
-spec calculate_diffs(gb_merkle_trees:tree(), gb_merkle_trees:tree()) -> list(#'Validator'{}).
-spec calculate_diffs(gb_merkle_trees:tree(), gb_merkle_trees:tree()) -> list(#'abci.Validator'{}).
calculate_diffs(New, Old) ->
KeysFun =
fun (Tree) ->
......@@ -196,11 +197,11 @@ calculate_diffs(New, Old) ->
[],
Tree)
end,
DeletedEntries = [#'Validator'{pub_key=#'PubKey'{data=PK, type="ed25519"}, power=0} || PK <- KeysFun(Old) -- KeysFun(New)],
DeletedEntries = [#'abci.Validator'{pub_key=#'abci.PubKey'{data=PK, type="ed25519"}, power=0} || PK <- KeysFun(Old) -- KeysFun(New)],
NewEntries =
[begin
<<VP, _/binary>> = Value,
#'Validator'{pub_key=#'PubKey'{data=PK, type="ed25519"}, power=VP}
#'abci.Validator'{pub_key=#'abci.PubKey'{data=PK, type="ed25519"}, power=VP}
end || {PK, Value} <- gb_merkle_trees:to_orddict(New) -- gb_merkle_trees:to_orddict(Old)],
NewEntries ++ DeletedEntries.
......
......@@ -71,36 +71,25 @@ hexstr_to_bin([X,Y|Tail], Acc) ->
{ok, [Byte], []} = io_lib:fread("~16u", [X,Y]),
hexstr_to_bin(Tail, <<Acc/binary, Byte>>).
-spec timestamp_to_iso(timestamp()) -> binary().
timestamp_to_iso(Timestamp) ->
Seconds1970 = Timestamp div 1000,
GregorianSeconds = calendar:date_to_gregorian_days(1970, 1, 1) * 86400 + Seconds1970,
Datetime = calendar:gregorian_seconds_to_datetime(GregorianSeconds),
iso8601:format(Datetime).
-spec now_timestamp() -> timestamp().
now_timestamp() ->
(calendar:datetime_to_gregorian_seconds(calendar:universal_time()) - calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}})) * 1000.
-spec data_to_genesis_json(data()) -> binary().
data_to_genesis_json(Data) ->
data_to_genesis_json(Data, now_timestamp()).
data_to_genesis_json(Data, ercoin_timestamp:now()).
%% @doc Convert data and a starting timestamp to a genesis.json file for Tendermint.
-spec data_to_genesis_json(data(), timestamp()) -> binary().
data_to_genesis_json(Genesis, Timestamp) ->
Options = [pretty],
Validators =
[{[{<<"power">>, Power},
[{[{<<"power">>, integer_to_binary(Power)},
{<<"name">>, <<"">>},
{<<"pub_key">>,
{[{<<"type">>, <<"AC26791624DE60">>},
{[{<<"type">>, <<"tendermint/PubKeyEd25519">>},
{<<"value">>, base64:encode(PK)}]}}]}
|| {PK, <<Power/integer, _/binary>>} <- gb_merkle_trees:to_orddict(Genesis#data.validators)],
ToEncode =
{[{<<"app_hash">>, <<"">>},
{<<"app_state">>, base64:encode(term_to_binary(Genesis, [{compressed, 9}]))},
{<<"genesis_time">>, timestamp_to_iso(Timestamp)},
{<<"genesis_time">>, ercoin_timestamp:to_iso(Timestamp)},
{<<"chain_id">>, <<"ercoin-test">>},
{<<"validators">>, Validators}]},
jiffy:encode(ToEncode, Options).
......@@ -111,11 +100,11 @@ sk_to_priv_validator_json(SK) ->
Address = binary:part(crypto:hash(sha256, PK), 0, 20),
ToEncode =
{[{<<"address">>, binary_to_hex(Address)},
{<<"last_height">>, 0},
{<<"last_round">>, 0},
{<<"last_height">>, <<"0">>},
{<<"last_round">>, <<"0">>},
{<<"last_step">>, 0},
{<<"priv_key">>,
[{<<"type">>, <<"954568A3288910">>},
[{<<"type">>, <<"tendermint/PrivKeyEd25519">>},
{<<"value">>, base64:encode(SK)}]}]},
jiffy:encode(ToEncode, Options).
......
......@@ -18,8 +18,8 @@
-export(
[perform/2]).
-spec perform(abci:'RequestQuery'(), data()) -> abci:'ResponseQuery'().
perform(#'RequestQuery'{path=Path, data=QueryData}, #data{accounts=Accounts}) ->
-spec perform(abci:'abci.RequestQuery'(), data()) -> abci:'abci.ResponseQuery'().
perform(#'abci.RequestQuery'{path=Path, data=QueryData}, #data{accounts=Accounts}) ->
{Code, ResponseValue, Error} =
case iolist_to_binary(Path) of
<<"account">> ->
......@@ -32,4 +32,4 @@ perform(#'RequestQuery'{path=Path, data=QueryData}, #data{accounts=Accounts}) ->
_ ->
{?BAD_REQUEST, <<>>, []}
end,
#'ResponseQuery'{code=Code, value=ResponseValue, log=Error}.
#'abci.ResponseQuery'{code=Code, value=ResponseValue, log=Error}.
%% Licensed under the Apache License, Version 2.0 (the “License”);
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an “AS IS” BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-module(ercoin_timestamp).
-export(
[from_iso/1,
from_protobuf/1,
now/0,
to_iso/1,
to_protobuf/1]).
-include_lib("include/ercoin.hrl").
-include_lib("abci_server/include/abci.hrl").
-spec to_iso(timestamp()) -> binary().
to_iso(Timestamp) ->
'Elixir.DateTime':to_iso8601(
'Elixir.DateTime':'from_unix!'(Timestamp, millisecond),
extended).
-spec now() -> timestamp().
now() ->
'Elixir.DateTime':to_unix('Elixir.DateTime':utc_now(), millisecond).
-spec from_iso(binary()) -> timestamp().
from_iso(ISO) ->
{ok, DateTime, 0} = 'Elixir.DateTime':'from_iso8601'(ISO),
'Elixir.DateTime':to_unix(DateTime, millisecond).
-spec from_protobuf(#'google.protobuf.Timestamp'{}) -> timestamp().
from_protobuf(#'google.protobuf.Timestamp'{seconds=Secs, nanos=Nanos}) ->
Secs * 1000 + Nanos div 1000000.
-spec to_protobuf(timestamp()) -> #'google.protobuf.Timestamp'{}.
to_protobuf(Timestamp) ->
#'google.protobuf.Timestamp'{
seconds=Timestamp div 1000,
nanos=(Timestamp rem 1000) * 1000000}.
......@@ -16,7 +16,9 @@
-export(
[absencies/2,
draw/1]).
address_to_tendermint/1,
draw/1,
key_value_by_tendermint_address/2]).
-spec voting_resolution(data()) -> pos_integer().
voting_resolution(_) ->
......@@ -61,3 +63,19 @@ draw(Data=#data{accounts=Accounts, height=Height, epoch_length=EpochLength}) ->
absencies(Address, Validators) ->
<<_, Absencies:3/unit:8, _/binary>> = gb_merkle_trees:lookup(Address, Validators),
Absencies.
-spec address_to_tendermint(address()) -> binary().
%% @doc Convert validator’s public key to Tendermint address.
address_to_tendermint(Address) ->
<<TendermintAddress:20/binary, _/binary>> = crypto:hash(sha256, Address),
TendermintAddress.
-spec tendermint_address_map(gb_merkle_trees:tree()) -> #{binary() => address()}.
%% @doc Return a map of Tendermint addresses to Ercoin addresses (validators’ public keys).
tendermint_address_map(Validators) ->
maps:from_list([{address_to_tendermint(Address), Address} || {Address, _} <- gb_merkle_trees:to_orddict(Validators)]).
-spec key_value_by_tendermint_address(binary(), data()) -> {address(), binary()}.
key_value_by_tendermint_address(TAddress, #data{validators=Validators}) ->
PK = maps:get(TAddress, tendermint_address_map(Validators)),
{PK, gb_merkle_trees:lookup(PK, Validators)}.
......@@ -19,14 +19,14 @@
-spec end_block(data()) -> data().
end_block(Data) ->
{keep_state, NewData, {reply, "from", #'ResponseEndBlock'{}}} =
ercoin_abci:handle_event({call, "from"}, #'RequestEndBlock'{}, committing, Data),
{keep_state, NewData, {reply, "from", #'abci.ResponseEndBlock'{}}} =
ercoin_abci:handle_event({call, "from"}, #'abci.RequestEndBlock'{}, committing, Data),
NewData.
-spec apply_diffs(list(#'Validator'{}), gb_merkle_trees:tree()) -> gb_merkle_trees:tree().
-spec apply_diffs(list(#'abci.Validator'{}), gb_merkle_trees:tree()) -> gb_merkle_trees:tree().
apply_diffs([], Validators) ->
Validators;
apply_diffs([#'Validator'{power=VP, pub_key=#'PubKey'{data=PubKey, type="ed25519"}}|Diffs], Validators) ->
apply_diffs([#'abci.Validator'{power=VP, pub_key=#'abci.PubKey'{data=PubKey, type="ed25519"}}|Diffs], Validators) ->
NewValidators =
case VP of
0 ->
......@@ -52,15 +52,15 @@ prop_init_chain_sets_data_and_responds_with_validators() ->
Data=#data{validators=Validators},
data(),
begin
{next_state, gossiping, ResponseData, {reply, foo, #'ResponseInitChain'{validators=ResponseValidators}}} =
{next_state, gossiping, ResponseData, {reply, foo, #'abci.ResponseInitChain'{validators=ResponseValidators}}} =
ercoin_abci:handle_event(
{call, foo},
#'RequestInitChain'{
#'abci.RequestInitChain'{
app_state_bytes=data_to_app_state_bytes(Data)},
uninitialized,
none),
ResponseData =:= Data andalso
ResponseValidators =:= [#'Validator'{power=Power, pub_key=#'PubKey'{data=PK, type="ed25519"}} || {PK, <<Power, _/binary>>} <- gb_merkle_trees:to_orddict(Validators)]
ResponseValidators =:= [#'abci.Validator'{power=Power, pub_key=#'abci.PubKey'{data=PK, type="ed25519"}} || {PK, <<Power, _/binary>>} <- gb_merkle_trees:to_orddict(Validators)]
end).
prop_validators_at_end_block() ->
......@@ -70,8 +70,8 @@ prop_validators_at_end_block() ->
begin
{keep_state,
#data{validators=NewValidators},
{reply, "from", #'ResponseEndBlock'{validator_updates=Diffs}}} =
ercoin_abci:handle_event({call, "from"}, #'RequestEndBlock'{}, committing, Data),
{reply, "from", #'abci.ResponseEndBlock'{validator_updates=Diffs}}} =
ercoin_abci:handle_event({call, "from"}, #'abci.RequestEndBlock'{}, committing, Data),
NormalizationFun =
fun (Validators2) ->
gb_merkle_trees:foldr(
......@@ -235,10 +235,10 @@ prop_deliver_tx_handles_binary_in_regard_to_data() ->
[fun ercoin_tx_gen:data_with_tx_bin/0,
fun ercoin_tx_gen:data_with_invalid_tx_bin/0]),
begin
{keep_state, NewData, {reply, "from", #'ResponseDeliverTx'{code=ErrorCode}}} =
{keep_state, NewData, {reply, "from", #'abci.ResponseDeliverTx'{code=ErrorCode}}} =
ercoin_abci:handle_event(
{call, "from"},
#'RequestDeliverTx'{
#'abci.RequestDeliverTx'{
tx=MaybeTxBin},
committing,
Data),
......@@ -256,10 +256,10 @@ prop_check_tx_handles_binary_in_regard_to_mempool_data() ->
fun ercoin_tx_gen:data_with_invalid_tx_bin/0]),
elements([gossiping, committing])},
begin
{keep_state, #data{mempool_data=NewMempoolData}, {reply, "from", #'ResponseCheckTx'{code=ErrorCode}}} =
{keep_state, #data{mempool_data=NewMempoolData}, {reply, "from", #'abci.ResponseCheckTx'{code=ErrorCode}}} =
ercoin_abci:handle_event(
{call, "from"},
#'RequestCheckTx'{
#'abci.RequestCheckTx'{
tx=MaybeTxBin},
StateName,
#data{mempool_data=MempoolData}),
......@@ -276,10 +276,10 @@ prop_tx_puts_fee_into_fee_deposits() ->
FeeLong = ercoin_fee:long(Tx, Data),
{keep_state,
#data{fee_deposit_short=NewFeeDepositShort, fee_deposit_long=NewFeeDepositLong},
{reply, "from", #'ResponseDeliverTx'{code=?OK}}} =
{reply, "from", #'abci.ResponseDeliverTx'{code=?OK}}} =
ercoin_abci:handle_event(
{call, "from"},
#'RequestDeliverTx'{
#'abci.RequestDeliverTx'{
tx=ercoin_tx:serialize(Tx)},
committing,
Data),
......@@ -292,8 +292,8 @@ prop_info_responds_with_app_hash_and_height_when_gossiping() ->
Data=#data{height=Height},
data(),
begin
{keep_state_and_data, {reply, "from", #'ResponseInfo'{last_block_height=ResponseHeight, last_block_app_hash=AppHash}}} =
ercoin_abci:handle_event({call, "from"}, #'RequestInfo'{}, gossiping, Data),
{keep_state_and_data, {reply, "from", #'abci.ResponseInfo'{last_block_height=ResponseHeight, last_block_app_hash=AppHash}}} =
ercoin_abci:handle_event({call, "from"}, #'abci.RequestInfo'{}, gossiping, Data),
ResponseHeight =:= Height andalso AppHash =:= ercoin_abci:app_hash(Data)
end).
......@@ -302,32 +302,24 @@ prop_commit_responds_with_app_hash() ->
Data,
data(),
begin
{next_state, gossiping, NewData, [{reply, "from", #'ResponseCommit'{data=ResponseData}}|_]} =
ercoin_abci:handle_event({call, "from"}, #'RequestCommit'{}, committing, Data),
{next_state, gossiping, NewData, [{reply, "from", #'abci.ResponseCommit'{data=ResponseData}}|_]} =
ercoin_abci:handle_event({call, "from"}, #'abci.RequestCommit'{}, committing, Data),
ResponseData =:= ercoin_abci:app_hash(NewData)
end).
prop_begin_block_increments_absencies() ->
?FORALL(
{Data=#data{validators=Validators}, SigningValidators, Header},
{Data, BeginBlock=#'abci.RequestBeginBlock'{last_commit_info=#'abci.LastCommitInfo'{validators=SigningValidators}}},
?LET(
Data=#data{validators=Validators},
Data,
data(),
?LET(
{SignedList, Header},
{vector(gb_merkle_trees:size(Validators), bool()), header(Data)},
{Data,
[#'SigningValidator'{
signed_last_block=Signed,
validator=#'Validator'{pub_key=#'PubKey'{data=PK}, power=Power}}
|| {{PK, <<Power, _/binary>>}, Signed} <- lists:zip(gb_merkle_trees:to_orddict(Validators), SignedList)],
Header})),
{Data, begin_block(Data)}),
begin
{next_state, committing, #data{validators=ResponseValidators}, {reply, "from", #'ResponseBeginBlock'{}}} =
ercoin_abci:handle_event({call, "from"}, #'RequestBeginBlock'{validators=SigningValidators, header=Header}, gossiping, Data),
{next_state, committing, #data{validators=ResponseValidators}, {reply, "from", #'abci.ResponseBeginBlock'{}}} =
ercoin_abci:handle_event({call, "from"}, BeginBlock, gossiping, Data),
lists:all(
fun (#'SigningValidator'{signed_last_block=Signed, validator=#'Validator'{pub_key=#'PubKey'{data=PK}}}) ->
<<_, Absencies:3/unit:8, _/binary>> = gb_merkle_trees:lookup(PK, Validators),
fun (#'abci.SigningValidator'{signed_last_block=Signed, validator=#'abci.Validator'{address=TendermintAddress}}) ->
{PK, <<_, Absencies:3/unit:8, _/binary>>} = ercoin_validators:key_value_by_tendermint_address(TendermintAddress, Data),
<<_, ResponseAbsencies:3/unit:8, _/binary>> = gb_merkle_trees:lookup(PK, ResponseValidators),
case Signed of
true ->
......@@ -346,19 +338,20 @@ prop_begin_block_updates_timestamps() ->
height=Height,
epoch_length=EpochLength,
timestamp=Timestamp,
last_epoch_end=LastEpochEnd}, Header},
last_epoch_end=LastEpochEnd},
BeginBlock},
?LET(
Data,
data(),
{Data, header(Data)}),
{Data, begin_block(Data)}),
begin
Stage = Height rem EpochLength,
{next_state,
committing,
#data{timestamp=NewTimestamp, last_epoch_end=NewLastEpochEnd},
{reply, "from", #'ResponseBeginBlock'{}}} =
ercoin_abci:handle_event({call, "from"}, #'RequestBeginBlock'{header=Header}, gossiping, Data),
NewTimestamp =:= Header#'Header'.time andalso NewLastEpochEnd =:=
{reply, "from", #'abci.ResponseBeginBlock'{}}} =
ercoin_abci:handle_event({call, "from"}, BeginBlock, gossiping, Data),
NewTimestamp =:= ercoin_timestamp:from_protobuf(BeginBlock#'abci.RequestBeginBlock'.header#'abci.Header'.time) andalso NewLastEpochEnd =:=
case Stage of
0 ->
Timestamp;
......
......@@ -24,6 +24,7 @@
account_from/2,
address/0,
address_secret/0,
begin_block/1,
block_height/0,
choices/0,
data/0,
......@@ -31,7 +32,6 @@
data_sks_and_account/0,
data_sks_and_account/1,
data_with_account/0,
header/1,
valid_since/1,
valid_since/2,
vote/1,
......@@ -325,8 +325,23 @@ header(#data{timestamp=Timestamp}) ->
?LET(
{TimestampOffset},
{pos_integer()},
#'Header'{
time=Timestamp + TimestampOffset}).
#'abci.Header'{
time=ercoin_timestamp:to_protobuf(Timestamp + TimestampOffset)}).
begin_block(Data=#data{validators=Validators}) ->
?LET(
{Header, SignedList},
{header(Data),
vector(gb_merkle_trees:size(Validators), bool())},
begin
SigningValidators =[#'abci.SigningValidator'{
signed_last_block=Signed,
validator=#'abci.Validator'{address=ercoin_validators:address_to_tendermint(PK), power=Power}}
|| {{PK, <<Power, _/binary>>}, Signed} <- lists:zip(gb_merkle_trees:to_orddict(Validators), SignedList)],
#'abci.RequestBeginBlock'{
last_commit_info=#'abci.LastCommitInfo'{validators=SigningValidators},
header=Header}
end).
-spec filter_accounts(fun((account(), data()) -> boolean()), data()) -> list(account()).
filter_accounts(Pred, Data=#data{accounts=AccountsTree}) ->
......
......@@ -22,14 +22,14 @@
data_with_query_unknown/0]).
data_with_query_unknown() ->
{data(), #'RequestQuery'{path="non-existent", data= <<"foo">>}}.
{data(), #'abci.RequestQuery'{path="non-existent", data= <<"foo">>}}.
data_with_query_account_valid() ->
?LET(
{Data, Account},
data_with_account(),
{Data,
#'RequestQuery'{
#'abci.RequestQuery'{
path="account",
data=Account#account.address}}).
......@@ -38,7 +38,7 @@ data_with_query_account_not_existing() ->
{Data, Bin},
{data(), binary(32)},
{Data,
#'RequestQuery'{
#'abci.RequestQuery'{
path="account",
data=Bin}}).
......
......@@ -25,12 +25,12 @@
prop_account_query_returns_serialized_account() ->
?FORALL(
{Data, Query=#'RequestQuery'{data=Address}},
{Data, Query=#'abci.RequestQuery'{data=Address}},
data_with_query_account_valid(),
begin
Account = ercoin_account:get(Address, Data),
{Address, Value} = ercoin_account:serialize(Account),
#'ResponseQuery'{value=ResponseValue} =
#'abci.ResponseQuery'{value=ResponseValue} =
ercoin_query:perform(Query, Data),
Value =:= ResponseValue
end).
......
%% Licensed under the Apache License, Version 2.0 (the “License”);
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an “AS IS” BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-module(ercoin_timestamp_tests).
-include_lib("include/ercoin_test.hrl").
prop_timestamp_to_iso_and_back_conversion() ->
?FORALL(
Timestamp,
pos_integer(),
ercoin_timestamp:from_iso(ercoin_timestamp:to_iso(Timestamp)) =:= Timestamp).
prop_timestamp_to_protobuf_and_back_conversion() ->
?FORALL(
Timestamp,
pos_integer(),
ercoin_timestamp:from_protobuf(ercoin_timestamp:to_protobuf(Timestamp)) =:= Timestamp).