Solution 3 - maintaining vote counting and head collation on-chain
If we can move vote counting in-chain, the committee size problem could be solved by maintain period_notary_pool_len
in storage:
period_notary_pool_len
representnotary_pool_len
that will use for sampling current periodnotary_offset
represent the variation ofnotary_pool_len
during the current period. (Might be negative number)
p.s. there’s still a
notary_pool_len
which represents the real length.
The period_notary_pool_len
will be updated when the first time SMC is called with transaction per period, includes:
register_notary
deregister_notary
add_header
Then we can apply @NicLin 's voting checking.
- When the notaries try to do lookahead right after the period starts, they use
notary_pool_len = period_notary_pool_len + notary_offset
. - For the on-chain voting, using
period_notary_pool_len
in contract.
- Pros:
- Less on-chain gas spending for the proposer than Solution 2.
- Cons:
- When the case that index out of range, this seat will be given up.
- If
add_header
becomes off-chain in the future scheme, it will be tricky again. - Only the notary pool being snapshotted, so it’s possible that one
notary_1
deregisters and anothernotary_2
registers and takes the empty slot fromnotary_1
during one period. If there’s slashing condition for do-nothing notary, the innocentnotary_2
will be penalized?
Summary of Solution 3 + @vbuterin 's bitfield counting:
-
Add one storage in SMC:
last_period: public(int128)
records the period of the most recent success add_header message. -
Add a storage variable
current_vote: public(bytes32)
:- First bytes31: bitfield of who has voted and who has not. Each bit represent the iterating number in the
get_committee
function. - Last byte: a counter of the total number of eligible notaries that voted
- First bytes31: bitfield of who has voted and who has not. Each bit represent the iterating number in the
-
Add one
period_notary_pool_len
in storage to represent thenotary_pool_len
at the time of that the period just starts. -
Add a
SMC.settle_current_notary_len()
function to settleperiod_notary_pool_len
:def settle_current_notary_len() -> int128: self.period_notary_pool_len += self.notary_offset self.notary_offset = 0 self.last_period = current_period return self.period_notary_pool_len
-
Modify
SMC.register_notary
function:- If
self.last_period < current_period
, callself.settle_current_notary_len()
. self.natary_offset += 1
- If
-
Modify
SMC.deregister_notary
function:- If
self.last_period < current_period
, callself.settle_notary_len()
. natary_offset -= 1
- If
-
Modify
SMC.add_header
function. When the-first-proposer-per-period calls it:- If
self.last_period < current_period
, callself.settle_current_notary_len()
. - Resets
current_vote
- If
-
Add
check_eligible_notary(shard_id, period, index)
checks if the notary index is eligible:def check_eligible_notary(shard_id, period, index) -> bool: return msg.sender == self.notary_pool[sha3(h + index) % self.period_notary_pool_len]
- Another version for the notary to do lookahead message call only and it returns
index
if result >= 0:def lookahead_eligible_notary(shard_id, period, notary_pool_len) -> int128: for index in range(self.COMMITTEE_SIZE): if msg.sender == self.notary_pool[sha3(h + index) % notary_pool_len] return index return -1
- Another version for the notary to do lookahead message call only and it returns
-
Modify
SMC.submit_vote
function:- Checks the eligibility with
SMC.check_eligible_notary(shard_id, period, index)
- Updates
current_vote
:- Set the bit of
index
to1
- Increase last byte by 1
- Set the bit of
- If
current_vote
>= 2/3COMMITTEE_SIZE
, update head collation info on-chain.
- Checks the eligibility with