Skip to content
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

[INDY-992] Move bls tests to sdk #564

Merged
merged 18 commits into from
Mar 19, 2018
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plenum/common/messages/client_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
ChooseField, ConstantField, DestNodeField, VerkeyField, DestNymField, \
RoleField, TxnSeqNoField, IdentifierField, \
NonNegativeNumberField, SignatureField, MapField, LimitedLengthStringField, \
ProtocolVersionField, LedgerIdField
ProtocolVersionField, LedgerIdField, Base58Field
from plenum.common.messages.message_base import MessageValidator
from plenum.common.types import OPERATION, f
from plenum.config import ALIAS_FIELD_LIMIT, DIGEST_FIELD_LIMIT, \
Expand All @@ -22,7 +22,7 @@ class ClientNodeOperationData(MessageValidator):
(CLIENT_PORT, NetworkPortField(optional=True)),
(ALIAS, LimitedLengthStringField(max_length=ALIAS_FIELD_LIMIT)),
(SERVICES, IterableField(ChooseField(values=(VALIDATOR,)), optional=True)),
(BLS_KEY, LimitedLengthStringField(max_length=BLS_KEY_LIMIT, optional=True)),
(BLS_KEY, Base58Field(byte_lengths=(128,), optional=True)),
)

def _validate_message(self, dct):
Expand Down
2 changes: 1 addition & 1 deletion plenum/test/bls/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from plenum.common.constants import DOMAIN_LEDGER_ID
from plenum.common.util import get_utc_epoch
from plenum.test.bls.helper import generate_state_root

from plenum.test.pool_transactions.conftest import looper

participants = ["Node1", "Node2", "Node3"]
signature = "somefakesignaturesomefakesignaturesomefakesignature"
Expand Down
211 changes: 179 additions & 32 deletions plenum/test/bls/helper.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
import base58
import os

from common.serializers.serialization import state_roots_serializer
from plenum.common.constants import DOMAIN_LEDGER_ID, ALIAS, BLS_KEY
from crypto.bls.bls_crypto import BlsCryptoVerifier

Copy link
Contributor

Choose a reason for hiding this comment

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

remove empty lines between imports

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

from plenum.bls.bls_crypto_factory import create_default_bls_crypto_factory

from plenum.server.quorums import Quorums

from crypto.bls.bls_multi_signature import MultiSignatureValue

from state.pruning_state import PruningState

from plenum.test.node_request.helper import sdk_ensure_pool_functional

from common.serializers.serialization import state_roots_serializer, proof_nodes_serializer
from plenum.common.constants import DOMAIN_LEDGER_ID, ALIAS, BLS_KEY, STATE_PROOF, TXN_TYPE, MULTI_SIGNATURE, \
MULTI_SIGNATURE_PARTICIPANTS, MULTI_SIGNATURE_SIGNATURE, MULTI_SIGNATURE_VALUE
from plenum.common.keygen_utils import init_bls_keys
from plenum.common.messages.node_messages import Commit, Prepare, PrePrepare
from plenum.common.util import get_utc_epoch, randomString, random_from_alphabet
from plenum.test.helper import sendRandomRequests, waitForSufficientRepliesForRequests
from plenum.common.util import get_utc_epoch, randomString, random_from_alphabet, hexToFriendly
from plenum.test.helper import sendRandomRequests, waitForSufficientRepliesForRequests, sdk_send_random_and_check
from plenum.test.node_catchup.helper import waitNodeDataEquality, ensureClientConnectedToNodesAndPoolLedgerSame
from plenum.test.pool_transactions.helper import updateNodeData, new_client
from plenum.test.pool_transactions.helper import updateNodeData, sdk_send_update_node, \
sdk_pool_refresh
from stp_core.common.log import getlogger

logger = getlogger()


def generate_state_root():
Expand Down Expand Up @@ -45,7 +62,46 @@ def check_bls_multi_sig_after_send(looper, txnPoolNodeSet,

# 3. check how many multi-sigs are saved
for multi_sigs in multi_sigs_for_batch:
assert len(multi_sigs) == saved_multi_sigs_count,\
assert len(multi_sigs) == saved_multi_sigs_count, \
"{} != {}".format(len(multi_sigs), saved_multi_sigs_count)

# 3. check that bls multi-sig is the same for all nodes we get PrePrepare for (that is for all expect the last one)
for multi_sigs in multi_sigs_for_batch[:-1]:
if multi_sigs:
assert multi_sigs.count(multi_sigs[0]) == len(multi_sigs)


def sdk_check_bls_multi_sig_after_send(looper, txnPoolNodeSet,
sdk_pool_handle, sdk_wallet_handle,
saved_multi_sigs_count):
# at least two because first request could have no
# signature since state can be clear
number_of_requests = 3

# 1. send requests
# Using loop to avoid 3pc batching
state_roots = []
for i in range(number_of_requests):
sdk_send_random_and_check(looper, txnPoolNodeSet, sdk_pool_handle,
sdk_wallet_handle, 1)
waitNodeDataEquality(looper, txnPoolNodeSet[0], *txnPoolNodeSet[:-1])
state_roots.append(
state_roots_serializer.serialize(
bytes(txnPoolNodeSet[0].getState(DOMAIN_LEDGER_ID).committedHeadHash)))

# 2. get all saved multi-sigs
multi_sigs_for_batch = []
for state_root in state_roots:
multi_sigs = []
for node in txnPoolNodeSet:
multi_sig = node.bls_bft.bls_store.get(state_root)
if multi_sig:
multi_sigs.append(multi_sig)
multi_sigs_for_batch.append(multi_sigs)

# 3. check how many multi-sigs are saved
for multi_sigs in multi_sigs_for_batch:
assert len(multi_sigs) == saved_multi_sigs_count, \
"{} != {}".format(len(multi_sigs), saved_multi_sigs_count)

# 3. check that bls multi-sig is the same for all nodes we get PrePrepare for (that is for all expect the last one)
Expand Down Expand Up @@ -89,20 +145,20 @@ def calculate_multi_sig(creator, bls_bft_with_commits, quorums, pre_prepare):


def create_pre_prepare_params(state_root,
ledger_id = DOMAIN_LEDGER_ID,
ledger_id=DOMAIN_LEDGER_ID,
txn_root=None,
timestamp=None,
bls_multi_sig=None):
params= [0,
0,
0,
timestamp or get_utc_epoch(),
[('1' * 16, 1)],
0,
"random digest",
ledger_id,
state_root,
txn_root or '1' * 32]
params = [0,
0,
0,
timestamp or get_utc_epoch(),
[('1' * 16, 1)],
0,
"random digest",
ledger_id,
state_root,
txn_root or '1' * 32]
if bls_multi_sig:
params.append(bls_multi_sig.as_list())
return params
Expand All @@ -122,12 +178,14 @@ def create_commit_no_bls_sig(req_key):
params = create_commit_params(view_no, pp_seq_no)
return Commit(*params)


def create_commit_with_bls_sig(req_key, bls_sig):
view_no, pp_seq_no = req_key
params = create_commit_params(view_no, pp_seq_no)
params.append(bls_sig)
return Commit(*params)


def create_commit_bls_sig(bls_bft, req_key, pre_prepare):
view_no, pp_seq_no = req_key
params = create_commit_params(view_no, pp_seq_no)
Expand Down Expand Up @@ -159,8 +217,8 @@ def change_bls_key(looper, txnPoolNodeSet,

key_in_txn = \
new_blspk \
if not add_wrong \
else ''.join(random_from_alphabet(32, base58.alphabet))
if not add_wrong \
else ''.join(random_from_alphabet(32, base58.alphabet))

node_data = {
ALIAS: node.name,
Expand All @@ -174,6 +232,30 @@ def change_bls_key(looper, txnPoolNodeSet,
return new_blspk


def sdk_change_bls_key(looper, txnPoolNodeSet,
node,
sdk_pool_handle,
sdk_wallet_steward,
add_wrong=False,
new_bls=None):
new_blspk = init_bls_keys(node.keys_dir, node.name)
key_in_txn = new_bls or new_blspk \
if not add_wrong \
else base58.b58encode(randomString(128).encode())
node_dest = hexToFriendly(node.nodestack.verhex)
sdk_send_update_node(looper, sdk_wallet_steward,
sdk_pool_handle,
node_dest, node.name,
None, None,
None, None,
bls_key=key_in_txn,
services=None)
waitNodeDataEquality(looper, node, *txnPoolNodeSet[:-1])
Copy link
Contributor

Choose a reason for hiding this comment

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

you pass some node to the func, it could be any node from txnPoolNodeSet, but to check equality you exclude always the last one.
I think you need to exclude the node you pass to func but not the last one

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

sdk_pool_refresh(looper, sdk_pool_handle)
sdk_ensure_pool_functional(looper, txnPoolNodeSet, sdk_wallet_steward, sdk_pool_handle)
return new_blspk


def check_bls_key(blskey, node, nodes, add_wrong=False):
'''
Check that each node has the same and correct blskey for this node
Expand All @@ -195,24 +277,89 @@ def check_bls_key(blskey, node, nodes, add_wrong=False):

def check_update_bls_key(node_num, saved_multi_sigs_count,
looper, txnPoolNodeSet,
client_tdir,
poolTxnClientData,
stewards_and_wallets,
sdk_wallet_stewards,
sdk_wallet_client,
sdk_pool_handle,
add_wrong=False):
# 1. Change BLS key for a specified NODE
node = txnPoolNodeSet[node_num]
steward_client, steward_wallet = stewards_and_wallets[node_num]
new_blspk = change_bls_key(looper, txnPoolNodeSet, node,
steward_client, steward_wallet,
add_wrong)
sdk_wallet_steward = sdk_wallet_stewards[node_num]
new_blspk = sdk_change_bls_key(looper, txnPoolNodeSet,
node,
sdk_pool_handle,
sdk_wallet_steward,
add_wrong)

# 2. Check that all Nodes see the new BLS key value
check_bls_key(new_blspk, node, txnPoolNodeSet, add_wrong)

# 3. Check that we can send new requests and have correct multisigs
client, wallet = new_client(looper,
poolTxnClientData,
txnPoolNodeSet, client_tdir)
check_bls_multi_sig_after_send(looper, txnPoolNodeSet,
client, wallet,
saved_multi_sigs_count=saved_multi_sigs_count)
sdk_check_bls_multi_sig_after_send(looper, txnPoolNodeSet,
sdk_pool_handle, sdk_wallet_client,
saved_multi_sigs_count)


def validate_proof(result):
"""
Validates state proof
Copy link
Contributor

Choose a reason for hiding this comment

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

make normal indentation

"""
Copy link
Contributor

Choose a reason for hiding this comment

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

and here too

state_root_hash = result[STATE_PROOF]['root_hash']
state_root_hash = state_roots_serializer.deserialize(state_root_hash)
proof_nodes = result[STATE_PROOF]['proof_nodes']
if isinstance(proof_nodes, str):
proof_nodes = proof_nodes.encode()
proof_nodes = proof_nodes_serializer.deserialize(proof_nodes)
key, value = prepare_for_state(result)
valid = PruningState.verify_state_proof(state_root_hash,
key,
value,
proof_nodes,
serialized=True)
return valid


def prepare_for_state(result):
if result[TXN_TYPE] == "buy":
from plenum.test.test_node import TestDomainRequestHandler
key, value = TestDomainRequestHandler.prepare_buy_for_state(result)
return key, value


def validate_multi_signature(state_proof, txnPoolNodeSet):
"""
Validates multi signature
"""
multi_signature = state_proof[MULTI_SIGNATURE]
if not multi_signature:
logger.debug("There is a state proof, but no multi signature")
return False

participants = multi_signature[MULTI_SIGNATURE_PARTICIPANTS]
signature = multi_signature[MULTI_SIGNATURE_SIGNATURE]
value = MultiSignatureValue(
**(multi_signature[MULTI_SIGNATURE_VALUE])
).as_single_value()
quorums = Quorums(len(txnPoolNodeSet))
if not quorums.bls_signatures.is_reached(len(participants)):
logger.debug("There is not enough participants of "
"multi-signature")
return False
public_keys = []
for node_name in participants:
key = next(node.bls_bft.bls_crypto_signer.pk for node
in txnPoolNodeSet if node.name == node_name)
if key is None:
logger.debug("There is no bls key for node {}"
.format(node_name))
return False
public_keys.append(key)
_multi_sig_verifier = _create_multi_sig_verifier()
return _multi_sig_verifier.verify_multi_sig(signature,
value,
public_keys)


def _create_multi_sig_verifier() -> BlsCryptoVerifier:
verifier = create_default_bls_crypto_factory() \
.create_bls_crypto_verifier()
return verifier
Loading