Do not pay full rewards if blocks were delayed

This commit also makes apportionment functions support the case of 0
seats.
parent b8a31c2f
Pipeline #21913513 failed with stages
in 9 minutes and 46 seconds
......@@ -22,7 +22,7 @@ dep_gb_merkle_trees = git https://github.com/KrzysiekJ/gb_merkle_trees.git v0.2.
dep_jiffy = git https://github.com/davisp/jiffy.git 0.14.11
dep_libsodium = git https://github.com/potatosalad/erlang-libsodium.git 0.0.10
dep_nist_beacon = git https://gitlab.com/KrzysiekJ/nist_beacon v0.1.1
dep_triq = git https://github.com/triqng/triq.git babad
dep_triq = git https://gitlab.com/triq/triq.git e1000a857f1f3e650f842cd1eac3dd8cbf502d72
BUILD_DEPS = lfe lfe.mk
dep_lfe = git https://github.com/rvirding/lfe 2880c8a2
......
......@@ -153,9 +153,10 @@ The following Merkle tree is formed when calculating an application hash:
* Protocol number.
* Block height.
* POSIX timestamp of last block in miliseconds.
* POSIX timestamp of the last block in previous epoch in miliseconds.
* Short fee deposit.
* Long fee deposit.
* Validators’ hash.
* Hash of validators for the next block.
* Future validators’ hash.
* Fresh transactions’ hash.
......@@ -175,7 +176,7 @@ Account transaction create accounts or extend their validity.
Every transaction except a vote transaction deducts a fee from the account from which it is performed. Fees are calculated from validators’ votes. They are put into long fee deposit (fees per block) and short fee deposit (fees per tx and per byte).
At the end of every epoch, short fee deposit and part of long fee deposit are divided between those validators that have less than 2/3 of absencies in block signatures, proportionally to their voting power.
At the end of every epoch, short fee deposit and part of long fee deposit are divided between those validators that have less than 2/3 of absencies in block signatures, proportionally to their voting power. If the epoch lasted longer than expected, a ratio proportional to the relative delay is put into long fee deposit instead of being granted to validators.
When new epoch is reached, validator set is replaced by a new one which has been drawn previously. When quarter of epoch (rounded down) is reached, data is locked for the purpose of drawing new validators. When three quarters of epoch (rounded down) are reached, result of drawing is yielded into application state. From that point future validators are able to send fee votes.
......
{
"app_hash" : "",
"app_state": "g1AAAAHxeNrL4E1hYElJLElMZEz8kMgAgVm5DAwMCgwEQAZTIlMGC1jpg48zLtUXBaz/W87ny6r1dpLxq3Bh/5t9KucViz2rViz6DFZkxnzST0T+RO6V66bbtygZy4eYrTRZqrs+dKfplneBIivuZDCDlVktevSt/Lmivce7nVKX648yn33jaPjh71yGhS3f3s2dccAPpIiHgbFtAZAW9yh7wQDWVX2d1fdHzDJbSXUDbdcfXE83nvRps7588EEg2yS2pYmum6CGE+NQAajhIMAIYoN1Br63sq322aF14Jm0mPiEU/HMy1jfmUw+kuleX+E822SfSwZTCgNfalFyfmZefGpeSVF+QWUKg0BRak5mYlJOKkwIGGaMJDhF0QE1yBnRaUawUX/FdDrLeuuWBX40+ZHweeX6jYfFpIKUVi5/rmd0Oa0vTjGFgbM0LyU1LTMvNQUASNKl1A==",
"app_state": "g1AAAAH9eNrL4EthYElJLElMZEz8kMiQwsBZmpeSmpaZl5qSyACCWbkMDAwKDARABlMiUwYLWOmDjzMu1RcFrP9bzufLqvV2kvGrcGH/m30q5xWLPatWLPoMVmTGfNJPRP5E7pXrptu3KBnLh5itNFmquz50p+mWd4EiK+5kMIOVWS169K38uaK9x7udUpfrjzKffeNo+OHvXIaFLd/ezZ1xwA+kiIeBsW0BkBb3KHvBANZVfZ3V90fMMltJdQNt1x9cTzee9GmzvnzwQSDbJLalia6boIYT41ABqOEgwAhig3UGvreyrfbZoXXgmbSY+IRT8czLWN+ZTD6S6V5f4TzbZJ9LBlMKA19qUXJ+Zl58al5JUX5BZQqDQFFqTmZiUk4qTAgYZowkOEXRATXIGdFpRrBRf8V0Ost665YFfjT5kfB55fqNh8WkgpRWLn+uZ3Q5rS9OETmGAVv/qfQ=",
"genesis_time" : "0001-01-01T00:00:00.000Z",
"chain_id" : "ercoin-test",
"validators" : [
......
......@@ -82,6 +82,7 @@
{protocol=1 :: pos_integer(),
epoch_length :: 2..31536000,
height=0 :: block_height() | 0,
last_epoch_end :: timestamp(),
timestamp :: timestamp(),
%% Short deposit collects fees for current processing, long deposit collects fees for long term storage.
fee_deposit_short=0 :: fee(),
......
......@@ -9,7 +9,7 @@
(include-lib "include/apportionment.lfe")
(defspec (apportion 4)
(((list (score)) (pos_integer) (UNION 'undefined (pos_integer)) (list (pos_integer))) (list (result))))
(((list (score)) (non_neg_integer) (UNION 'undefined (pos_integer)) (list (pos_integer))) (list (result))))
(defun apportion (scores seats _ divisors-init)
(let* ((divisors-init-count (length divisors-init))
(divisors (++ divisors-init (lists:seq (+ 1 (* 2 divisors-init-count)) (- (* 2 seats) 1) 2)))
......@@ -29,12 +29,12 @@
seats-singular)))
(defspec (apportion 3)
(((list (score)) (pos_integer) (UNION 'undefined (pos_integer))) (list (result))))
(((list (score)) (non_neg_integer) (UNION 'undefined (pos_integer))) (list (result))))
(defun apportion (scores seats votes-sum)
(apportion scores seats votes-sum '()))
(defspec (apportion 2)
(((list (score)) (pos_integer)) (list (tuple (any) (pos_integer)))))
(((list (score)) (non_neg_integer)) (list (tuple (any) (pos_integer)))))
(defun apportion (scores seats)
(apportion scores seats 'undefined))
......@@ -87,12 +87,14 @@
(lists:sort (add-singular-seats-and-flip int-results part-seats-for))))
(defspec (apportion 3)
(((list (score)) (pos_integer) (pos_integer)) (list (tuple (any) (pos_integer)))))
(((list (score)) (non_neg_integer) (pos_integer)) (list (tuple (any) (pos_integer)))))
(defun apportion (scores seats votes-sum)
(apportion scores seats votes-sum (/ votes-sum seats)))
(case seats
(0 '())
(_ (apportion scores seats votes-sum (/ votes-sum seats)))))
(defspec (apportion 2)
(((list (score)) (pos_integer)) (list (tuple (any) (pos_integer)))))
(((list (score)) (non_neg_integer)) (list (tuple (any) (pos_integer)))))
(defun apportion (scores seats)
(let ((total-votes (lists:foldl (match-lambda (((tuple votes _) acc) (+ votes acc))) 0 scores)))
(apportion scores seats total-votes)))
......@@ -142,7 +144,7 @@
"If population of whole country goes up (preserving proportions), no state can lose seats."
(FORALL
(tuple scores seats scale-factor method)
(tuple (scores) (pos_integer) (pos_integer) 'sainte-lague)
(tuple (scores) (non_neg_integer) (pos_integer) 'sainte-lague)
(let* ((scores-scaled (lists:map (match-lambda (((tuple votes id)) (tuple (* scale-factor votes) id))) scores))
(apportionment (apply method 'apportion (list scores seats)))
(apportionment-scaled (apply method 'apportion (list scores-scaled seats))))
......@@ -155,7 +157,7 @@
(tuple scores-base (tuple (tuple vote-1 id-1) (tuple vote-2 id-2)) (tuple change-1 change-2) seats method)
(SUCHTHAT
(tuple scores-base (tuple (tuple vote-1 id-1) (tuple vote-2 id-2)) (tuple change-1 change-2) seats method)
(tuple (scores) (tuple (score) (score)) (tuple (pos_integer) (pos_integer)) (pos_integer) 'sainte-lague)
(tuple (scores) (tuple (score) (score)) (tuple (pos_integer) (pos_integer)) (non_neg_integer) 'sainte-lague)
(andalso (=/= id-1 id-2)
(> vote-2 0)
(> vote-1 0)
......@@ -179,7 +181,7 @@
"Every participant gets number of seats equal either to the floor or ceil of his share multiplied by total seats."
(FORALL
(tuple scores total-seats method)
(tuple (scores) (pos_integer) 'hare-niemeyer)
(tuple (scores) (non_neg_integer) 'hare-niemeyer)
(let ((results (apply method 'apportion (list scores total-seats))))
(lists:all
(match-lambda
......@@ -193,7 +195,7 @@
"Apportioned seats sum to the desired number of total seats."
(FORALL
(tuple scores seats method)
(tuple (scores) (pos_integer) (method))
(tuple (scores) (non_neg_integer) (method))
(=:= seats
(lists:foldl
(match-lambda (((tuple _ seats) acc) (+ seats acc)))
......@@ -204,7 +206,7 @@
"Apportioned seats are unique by id."
(FORALL
(tuple scores seats method)
(tuple (scores) (pos_integer) (method))
(tuple (scores) (non_neg_integer) (method))
(let ((results (apply method 'apportion (list scores seats))))
(=:= (length results)
(sets:size (sets:from_list (lc ((<- (tuple id _) results)) id)))))))
......@@ -213,7 +215,7 @@
"Apportioned seats are sorted."
(FORALL
(tuple scores seats method)
(tuple (scores) (pos_integer) (method))
(tuple (scores) (non_neg_integer) (method))
(let ((results (apply method 'apportion (list scores seats))))
(=:= results (lists:sort results)))))
......@@ -221,7 +223,7 @@
"In case of equal scores, problematic seats get assigned to one with higher id."
(FORALL
(tuple scores seats method)
(tuple (scores) (pos_integer) (method))
(tuple (scores) (non_neg_integer) (method))
(let ((results (apply method 'apportion (list scores seats))))
(lists:all
(match-lambda
......
This diff is collapsed.
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