Skip to content

Commit

Permalink
[INDY-992] Move bls tests to sdk (hyperledger#564)
Browse files Browse the repository at this point in the history
* Initial test integration

Signed-off-by: ArtObr <[email protected]>

* Two more files done

Signed-off-by: ArtObr <[email protected]>

* new test

Signed-off-by: ArtObr <[email protected]>

* 4 more folders done

Signed-off-by: ArtObr <[email protected]>

* two more files

Signed-off-by: ArtObr <[email protected]>

* some changes

Signed-off-by: ArtObr <[email protected]>

* More tests integrated. Problems: validator functions of client in test_state_proof; problem with wrong bls keys

Signed-off-by: ArtObr <[email protected]>

* Script fix. bls validation fix

Signed-off-by: ArtObr <[email protected]>

* little fix

Signed-off-by: ArtObr <[email protected]>

* Fix for bls validation tests. Not done: update_incorrect test and state_proof test

Signed-off-by: ArtObr <[email protected]>

* Only state_proof test left

Signed-off-by: ArtObr <[email protected]>

* Tests integration done

Signed-off-by: ArtObr <[email protected]>

* Import deletion. flake8 error fix.

Signed-off-by: ArtObr <[email protected]>

* Review fixes

Signed-off-by: ArtObr <[email protected]>

* Little fix

Signed-off-by: ArtObr <[email protected]>
  • Loading branch information
ArtObr authored and Andrew Nikitin committed Apr 10, 2018
1 parent 2137e1b commit 1530261
Show file tree
Hide file tree
Showing 21 changed files with 415 additions and 256 deletions.
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

0 comments on commit 1530261

Please sign in to comment.