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 all 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
178 changes: 141 additions & 37 deletions plenum/test/bls/helper.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
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
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 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.node_request.helper import sdk_ensure_pool_functional
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():
return base58.b58encode(os.urandom(32))


def check_bls_multi_sig_after_send(looper, txnPoolNodeSet,
client, wallet,
saved_multi_sigs_count):
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
Expand All @@ -26,8 +37,8 @@ def check_bls_multi_sig_after_send(looper, txnPoolNodeSet,
# Using loop to avoid 3pc batching
state_roots = []
for i in range(number_of_requests):
reqs = sendRandomRequests(wallet, client, 1)
waitForSufficientRepliesForRequests(looper, client, requests=reqs)
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(
Expand All @@ -45,7 +56,7 @@ 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)
Expand Down Expand Up @@ -89,20 +100,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 +133,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 +172,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 +187,32 @@ 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)
poolSetExceptOne = list(txnPoolNodeSet)
poolSetExceptOne.remove(node)
waitNodeDataEquality(looper, node, *poolSetExceptOne)
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 +234,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
"""
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
54 changes: 31 additions & 23 deletions plenum/test/bls/test_add_bls_key.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from plenum.server.quorums import Quorum
from plenum.test.bls.helper import check_update_bls_key
from plenum.test.pool_transactions.conftest import looper, clientAndWallet1, \
client1, wallet1, client1Connected

nodeCount = 4
nodes_wth_bls = 0
Expand All @@ -10,37 +8,44 @@
# As we use tests with Module scope, results from previous tests are accumulated, so
# rotating BLS keys one by one, eventually we will have all keys changed

def test_add_bls_one_node(looper, txnPoolNodeSet, client_tdir,
poolTxnClientData, stewards_and_wallets):
def test_add_bls_one_node(looper,
txnPoolNodeSet,
sdk_pool_handle,
sdk_wallet_stewards, sdk_wallet_client):
'''
Added BLS key for 1st Node;
do not expect that BLS multi-sigs are applied since no consensus (n-f)
'''
check_update_bls_key(node_num=0,
saved_multi_sigs_count=0,
looper=looper, txnPoolNodeSet=txnPoolNodeSet,
client_tdir=client_tdir,
poolTxnClientData=poolTxnClientData,
stewards_and_wallets=stewards_and_wallets)
sdk_wallet_stewards=sdk_wallet_stewards,
sdk_wallet_client=sdk_wallet_client,
sdk_pool_handle=sdk_pool_handle)



def test_add_bls_two_nodes(looper, txnPoolNodeSet, client_tdir,
poolTxnClientData, stewards_and_wallets):
def test_add_bls_two_nodes(looper,
txnPoolNodeSet,
sdk_pool_handle,
sdk_wallet_stewards,
sdk_wallet_client):
'''
Added BLS key for 1st and 2d Nodes;
do not expect that BLS multi-sigs are applied since no consensus (n-f)
'''
check_update_bls_key(node_num=1,
saved_multi_sigs_count=0,
looper=looper, txnPoolNodeSet=txnPoolNodeSet,
client_tdir=client_tdir,
poolTxnClientData=poolTxnClientData,
stewards_and_wallets=stewards_and_wallets)
sdk_wallet_stewards=sdk_wallet_stewards,
sdk_wallet_client=sdk_wallet_client,
sdk_pool_handle=sdk_pool_handle)


def test_add_bls_three_nodes(looper, txnPoolNodeSet, client_tdir,
poolTxnClientData, stewards_and_wallets):
def test_add_bls_three_nodes(looper,
txnPoolNodeSet,
sdk_pool_handle,
sdk_wallet_stewards,
sdk_wallet_client):
'''
Added BLS key for 1st, 2d and 3d Nodes;
expect that BLS multi-sigs are applied since we have consensus now (3=n-f)
Expand All @@ -52,20 +57,23 @@ def test_add_bls_three_nodes(looper, txnPoolNodeSet, client_tdir,
check_update_bls_key(node_num=2,
saved_multi_sigs_count=4,
looper=looper, txnPoolNodeSet=txnPoolNodeSet,
client_tdir=client_tdir,
poolTxnClientData=poolTxnClientData,
stewards_and_wallets=stewards_and_wallets)
sdk_wallet_stewards=sdk_wallet_stewards,
sdk_wallet_client=sdk_wallet_client,
sdk_pool_handle=sdk_pool_handle)


def test_add_bls_all_nodes(looper, txnPoolNodeSet, client_tdir,
poolTxnClientData, stewards_and_wallets):
def test_add_bls_all_nodes(looper,
txnPoolNodeSet,
sdk_pool_handle,
sdk_wallet_stewards,
sdk_wallet_client):
'''
Eventually added BLS key for all Nodes;
expect that BLS multi-sigs are applied since we have consensus now (4 > n-f)
'''
check_update_bls_key(node_num=3,
saved_multi_sigs_count=4,
looper=looper, txnPoolNodeSet=txnPoolNodeSet,
client_tdir=client_tdir,
poolTxnClientData=poolTxnClientData,
stewards_and_wallets=stewards_and_wallets)
sdk_wallet_stewards=sdk_wallet_stewards,
sdk_wallet_client=sdk_wallet_client,
sdk_pool_handle=sdk_pool_handle)
Loading