Skip to content

ST-623 -- Init Commit multi-sig process #1325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Sep 13, 2019
Merged

Conversation

KitHat
Copy link
Contributor

@KitHat KitHat commented Sep 5, 2019

Signed-off-by: Nikita Khateev [email protected]

@@ -92,6 +97,36 @@ def update_commit(self, commit_params, pre_prepare: PrePrepare):
logger.debug("{}{} signed COMMIT {} for state {} with sig {}"
.format(BLS_PREFIX, self, commit_params, state_root_hash, bls_signature))
commit_params.append(bls_signature)

audit_ledger = self._database_manager.get_ledger(AUDIT_LEDGER_ID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have unit tests for the new functionality?

Nikita Khateev and others added 8 commits September 9, 2019 19:31
Signed-off-by: Nikita Khateev <[email protected]>
Signed-off-by: Nikita Khateev <[email protected]>
Signed-off-by: Nikita Khateev <[email protected]>

# Conflicts:
#	plenum/common/messages/node_messages.py
Signed-off-by: Nikita Khateev <[email protected]>
Signed-off-by: Nikita Khateev <[email protected]>
Signed-off-by: Nikita Khateev <[email protected]>
@KitHat
Copy link
Contributor Author

KitHat commented Sep 10, 2019

test me please

@lampkin-diet
Copy link

test this please

@@ -48,6 +62,10 @@ def validate_prepare(self, prepare: Prepare, sender):

@measure_time(MetricsName.BLS_VALIDATE_COMMIT_TIME)
def validate_commit(self, commit: Commit, sender, pre_prepare: PrePrepare):
if f.BLS_MULTI_SIGS.nm in commit:
if not list(filter(lambda sig: self._validate_signature(sender, sig, pre_prepare), commit.blsSigs)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter here returns all signatures for which validation succeeded, so if it's empty then either none of them succeeded, or there were no sigs at all. So, according to existing logic:

  1. We return CM_BLS_SIG_WRONG if all sigs are valid
  2. We return CM_BLS_SIG_WRONG if there are no sigs
  3. We don't return CM_BLS_SIG_WRONG if some but not all sigs are invalid
  4. We don't return CM_BLS_SIG_WRONG if all sigs are invalid

@@ -68,6 +86,8 @@ def update_pre_prepare(self, pre_prepare_params, ledger_id):
pre_prepare_params.append(self._bls_latest_multi_sig.as_list())
self._bls_latest_multi_sig = None
# Send signature in COMMITs only
if self._all_bls_latest_multi_sigs is not None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be that _bls_latest_multi_sig is False/None (so that we call return), but _all_bls_latest_multi_sigs is not None?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this

@@ -48,6 +62,10 @@ def validate_prepare(self, prepare: Prepare, sender):

@measure_time(MetricsName.BLS_VALIDATE_COMMIT_TIME)
def validate_commit(self, commit: Commit, sender, pre_prepare: PrePrepare):
if f.BLS_MULTI_SIGS.nm in commit:
if not list(filter(lambda sig: self._validate_signature(sender, sig, pre_prepare), commit.blsSigs)):
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can not call return here since f.BLS_SIG.nm needs to be set latter

@@ -115,6 +153,28 @@ def process_commit(self, commit: Commit, sender):
self._signatures[key_3PC] = {}
self._signatures[key_3PC][self.get_node_name(sender)] = commit.blsSig

if f.BLS_SIGS.nm not in commit:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be that commit.blsSig is None (so we called return), but commit.blsSigs is not None ?

self._signatures = {}
self._all_signatures = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need self._all_signatures and self._signatures? (self._all_bls_latest_multi_sigs and self._bls_latest_multi_sig)?
Can we make self._signatures (self._bls_latest_multi_sig) to be a special case in self._all_signatures (self._all_bls_latest_multi_sigs)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have thought about it. This way we will always need to fetch the correct ledger from _all_signatures according to PrePrepare. On the other hand we have some code duplication -- but it is pretty obvious and we will remove it with the next release and there will be no problems.

)
)
if sigs_invalid:
self._all_signatures.pop(key_3PC, None)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method name can_do_something needs to do only the checks, not modifications. So, code like self._all_signatures.pop looks really suspicious here.

sigs_for_request = self._all_signatures[key_3PC]
sigs_invalid = list(
filter(
lambda item: not quorums.bls_signatures.is_reached(len(list(item[1].values()))),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the following is more clear:

lambda ledger_id, sigs: not quorums.bls_signatures.is_reached(len(sigs))

sigs_for_request.items()
)
)
if sigs_invalid:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we have quorum for some ledgers, not for all? Currently False is returned, but maybe we should be able to calculate multi-sig for the sigs we have quorum for?

@@ -339,6 +372,81 @@ def test_process_order(bls_bft_replicas, pre_prepare_no_bls, quorums):
pre_prepare_no_bls)


# ------ MULTIPLE MULTI_SIGS ------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have tests where we have a mix of multiple and one sigs?

create_audit_txn_with_multiple_ledgers):
for sender_bls_bft_replica in bls_bft_replicas:
for verifier_bls_bft_replica in bls_bft_replicas:
assert not verifier_bls_bft_replica.validate_pre_prepare(pre_prepare_with_bls_multi,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add more tests for validation. For example, when we have multiple sigs, and some of them valid while some are not.

key = (0, 0)
for sender_bls_bft in bls_bft_replicas:
fake_sig = base58.b58encode(b"somefakesignaturesomefakesignaturesomefakesignature").decode("utf-8")
commit = create_commit_with_bls_sigs(key, fake_sig)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have multiple sigs here?
Please add more tests for validation:

  • when we really have more than 1 sig
  • when some of this sigs are valid and some are not
  • when there is multi-sig field, but it's empty

@@ -1222,7 +1222,8 @@ def create_pre_prepare_params(state_root,
pp_seq_no=0,
inst_id=0,
audit_txn_root=None,
reqs=None):
reqs=None,
bls_multi_sigs=[]):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to include bls_multi_sigs into all test helpers for creation of PrePrepare. If it's not specified, a defualt can be added (like [bls_sig]).

@@ -1271,6 +1274,14 @@ def create_commit_with_bls_sig(req_key, bls_sig):
return Commit(*params)


def create_commit_with_bls_sigs(req_key, bls_sig):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to include bls_multi_sigs into all test helpers for creation of Commit. If it's not specified, a defualt can be added (like [bls_sig]).

Nikita Khateev added 2 commits September 11, 2019 16:21
Signed-off-by: Nikita Khateev <[email protected]>
multi_sig = MultiSignature.from_list(*sig)
if not self._validate_multi_sig(multi_sig):
return BlsBftReplica.PPR_BLS_MULTISIG_WRONG
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think return here needs to be removed sine we may have both BLS_MULTI_SIGS and BLS_MULTI_SIG

@@ -68,6 +95,8 @@ def update_pre_prepare(self, pre_prepare_params, ledger_id):
pre_prepare_params.append(self._bls_latest_multi_sig.as_list())
self._bls_latest_multi_sig = None
# Send signature in COMMITs only
if self._all_bls_latest_multi_sigs is not None:
pre_prepare_params.append([val.as_list() for val in self._all_bls_latest_multi_sigs])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we set _all_bls_latest_multi_sigs to None like we do for _bls_latest_multi_sig ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -1241,6 +1242,8 @@ def create_pre_prepare_params(state_root,
audit_txn_root or generate_state_root()]
if bls_multi_sig:
params.append(bls_multi_sig.as_list())
if bls_multi_sigs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If bls_multi_sigs=[] (default), then this code will not be called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this as well

Nikita Khateev added 3 commits September 12, 2019 12:31
Signed-off-by: Nikita Khateev <[email protected]>
Signed-off-by: Nikita Khateev <[email protected]>
Signed-off-by: Nikita Khateev <[email protected]>
@@ -1244,6 +1244,8 @@ def create_pre_prepare_params(state_root,
params.append(bls_multi_sig.as_list())
if bls_multi_sigs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this needs to be

create_pre_prepare_params(.....,   bls_multi_sigs=None)
......
if bls_multi_sigs is not None:
    params.append(bls_multi_sig.as_list())
elif bls_multi_sig:
    params.append([bls_multi_sig.as_list()])

Nikita Khateev added 2 commits September 12, 2019 17:39
Signed-off-by: Nikita Khateev <[email protected]>
Signed-off-by: Nikita Khateev <[email protected]>
@@ -62,7 +62,7 @@ def validate_prepare(self, prepare: Prepare, sender):
@measure_time(MetricsName.BLS_VALIDATE_COMMIT_TIME)
def validate_commit(self, commit: Commit, sender, pre_prepare: PrePrepare):
if f.BLS_SIGS.nm in commit:
audit_txn = self._get_correct_audit_transaction(pre_prepare.ledgerId, pre_prepare.stateRootHash)
audit_txn = self._get_correct_audit_transaction(pre_prepare)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that audit_txn contains the same number of changes (length of AUDIT_TXN_STATE_ROOT) as blsSigs? Otherwise a KeyError may be raised here.

@KitHat
Copy link
Contributor Author

KitHat commented Sep 13, 2019

test this please

@ashcherbakov ashcherbakov merged commit 06089ae into hyperledger:master Sep 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants