Skip to content

Master #59

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 3 commits into from
Oct 10, 2017
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
3 changes: 1 addition & 2 deletions ci/code-validation.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ FROM ubuntu:16.04
ARG uid=1000

# Install environment
RUN apt-get update -y
RUN apt-get install -y \
RUN apt-get update -y && apt-get install -y \
git \
wget \
python3.5 \
Expand Down
14 changes: 9 additions & 5 deletions plenum/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ def __init__(self,
logger.debug("total plugins loaded in client: {}".format(tp))

self._multi_sig_verifier = self._create_multi_sig_verifier()
self._read_only_requests = set()

@lazy_field
def _bls_register(self):
Expand Down Expand Up @@ -276,11 +277,14 @@ async def prod(self, limit) -> int:
def submitReqs(self, *reqs: Request) -> List[Request]:
requests = []
errs = []

for request in reqs:
if (self.mode == Mode.discovered and self.hasSufficientConnections) or (
request.isForced() and self.hasAnyConnections):
logger.debug(
'Client {} sending request {}'.format(self, request))
if (self.mode == Mode.discovered and self.hasSufficientConnections) or \
(self.hasAnyConnections and
(request.txn_type in self._read_only_requests or request.isForced())):

logger.debug('Client {} sending request {}'
.format(self, request))
stat, err_msg = self.send(request)
if stat:
self.expectingFor(request)
Expand All @@ -292,7 +296,7 @@ def submitReqs(self, *reqs: Request) -> List[Request]:
else:
logger.debug(
"{} pending request since in mode {} and "
"connected to {} nodes". format(
"connected to {} nodes".format(
self, self.mode, self.nodestack.connecteds))
self.pendReqsTillConnection(request)
requests.append(request)
Expand Down
3 changes: 2 additions & 1 deletion plenum/client/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from jsonpickle.util import importable_name
from libnacl import crypto_secretbox_open, randombytes, \
crypto_secretbox_NONCEBYTES, crypto_secretbox
from plenum.common.constants import CURRENT_PROTOCOL_VERSION

from plenum.common.did_method import DidMethods, DefaultDidMethods
from plenum.common.exceptions import EmptyIdentifier
Expand Down Expand Up @@ -226,7 +227,7 @@ def signOp(self,
:param op: Operation to be signed
:return: a signed Request object
"""
request = Request(operation=op)
request = Request(operation=op, protocolVersion=CURRENT_PROTOCOL_VERSION)
return self.signRequest(request, identifier)

def _signerById(self, idr: Identifier):
Expand Down
8 changes: 6 additions & 2 deletions plenum/common/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Mapping, NamedTuple

from common.serializers.serialization import serialize_msg_for_signing
from plenum.common.constants import REQDIGEST, REQKEY, FORCE, CURRENT_PROTOCOL_VERSION
from plenum.common.constants import REQDIGEST, REQKEY, FORCE, TXN_TYPE
from plenum.common.messages.client_request import ClientMessageValidator
from plenum.common.types import f, OPERATION
from stp_core.types import Identifier
Expand All @@ -14,7 +14,7 @@ def __init__(self,
reqId: int = None,
operation: Mapping = None,
signature: str = None,
protocolVersion: int = CURRENT_PROTOCOL_VERSION):
protocolVersion: int = None):
self.identifier = identifier
self.reqId = reqId
self.operation = operation
Expand Down Expand Up @@ -87,6 +87,10 @@ def isForced(self):
force = self.operation.get(FORCE)
return str(force) == 'True'

@property
def txn_type(self):
return self.operation.get(TXN_TYPE)

def __hash__(self):
return hash(self.serialized())

Expand Down
5 changes: 3 additions & 2 deletions plenum/test/cli/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import plenum.cli.cli as cli
from plenum.client.wallet import Wallet
from plenum.common.constants import PRIMARY_SELECTION_PREFIX
from plenum.common.constants import PRIMARY_SELECTION_PREFIX, CURRENT_PROTOCOL_VERSION
from stp_core.common.constants import CONNECTION_PREFIX
from stp_core.common.util import Singleton
from stp_core.loop.eventually import eventually
Expand Down Expand Up @@ -275,7 +275,8 @@ def checkRequest(cli, operation):
lastReqId = wallet._getIdData().lastReqId

request = Request(identifier=wallet.defaultId,
reqId=lastReqId)
reqId=lastReqId,
protocolVersion=CURRENT_PROTOCOL_VERSION)

waitForSufficientRepliesForRequests(cli.looper, client,
requests=[request])
Expand Down
4 changes: 3 additions & 1 deletion plenum/test/cli/test_log_filtering.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import types

from plenum.common.constants import CURRENT_PROTOCOL_VERSION
from plenum.test.cli.helper import checkRequest
from plenum.test.helper import waitForSufficientRepliesForRequests
from plenum.common.request import Request
Expand All @@ -20,7 +21,8 @@ def handleOneNodeMsg(self, wrappedMsg, excludeFromCli=None):
cli.enterCmd('client {} send {}'.format(client.name, msg))

request = Request(identifier=wallet.defaultId,
reqId=wallet._getIdData().lastReqId)
reqId=wallet._getIdData().lastReqId,
protocolVersion=CURRENT_PROTOCOL_VERSION)

waitForSufficientRepliesForRequests(cli.looper, client,
requests=[request])
Expand Down
47 changes: 47 additions & 0 deletions plenum/test/client/test_client_sends_get_request_to_one_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import random

from plenum.test.client.conftest import passThroughReqAcked1

from plenum.test.helper import sendReqsToNodesAndVerifySuffReplies, stopNodes, waitForSufficientRepliesForRequests, \
send_signed_requests
from plenum.test.malicious_behaviors_client import \
genDoesntSendRequestToSomeNodes
from plenum.test.node_catchup.helper import waitNodeDataEquality


nodeCount = 4
clientFault = genDoesntSendRequestToSomeNodes("AlphaC")
reqAcked1 = passThroughReqAcked1


def test_client_sends_get_request_to_one_node(looper,
client1,
wallet1,
nodeSet):
"""
Check that read only equest can be sent
without having connection to all nodes
"""
client = client1
wallet = wallet1

nodes_to_stop = list(nodeSet)[1:]
stopNodes(nodes_to_stop, looper)

initial_submit_count = client.spylog.count(client.submitReqs)
initial_send_count = client.spylog.count(client.send)

def sign_and_send(op):
signed = wallet.signOp(op)
send_signed_requests(client, [signed])

buy = {'type': 'buy', 'amount': random.randint(10, 100)}
sign_and_send(buy)
assert initial_submit_count + 1 == client.spylog.count(client.submitReqs)
assert initial_send_count == client.spylog.count(client.send)

get_buy = {'type': 'get_buy'}
client._read_only_requests.add('get_buy')
sign_and_send(get_buy)
assert initial_submit_count + 2 == client.spylog.count(client.submitReqs)
assert initial_send_count + 1 == client.spylog.count(client.send)
53 changes: 38 additions & 15 deletions plenum/test/client/test_protocol_version.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,69 @@
import pytest
from plenum.common.constants import CURRENT_PROTOCOL_VERSION
from plenum.test.helper import sendRandomRequests, waitForSufficientRepliesForRequests, signed_random_requests, \
send_signed_requests, checkReqNackWithReason
from plenum.common.request import Request
from plenum.test.helper import waitForSufficientRepliesForRequests, \
send_signed_requests, checkReqNackWithReason, random_request_objects, \
sign_request_objects, signed_random_requests, random_requests
from plenum.test.pool_transactions.conftest import looper, clientAndWallet1, \
client1, wallet1, client1Connected
from stp_core.loop.eventually import eventually


@pytest.yield_fixture(scope="function", params=['1', '2'])
def request_num(request):
return int(request.param)

def test_request_no_protocol_version(tconf, looper, txnPoolNodeSet,
client1, client1Connected,
wallet1):
reqs = signed_random_requests(wallet1, 2)
wallet1,
request_num):
reqs = random_request_objects(request_num, protocol_version=None)
reqs = sign_request_objects(wallet1, reqs)
for req in reqs:
req.protocolVersion = None
assert req.protocolVersion is None

send_signed_requests(client1, reqs)
waitForSufficientRepliesForRequests(looper, client1, requests=reqs)


def test_version_set_by_default(tconf, looper, txnPoolNodeSet,
def test_version_not_set_by_default(tconf, looper, txnPoolNodeSet,
client1, client1Connected,
wallet1):
reqs = signed_random_requests(wallet1, 1)
assert reqs[0].protocolVersion
wallet1,
request_num):
req_dicts = random_requests(request_num)
reqs = [Request(operation=op) for op in req_dicts]
for req in reqs:
assert req.protocolVersion is None
reqs = sign_request_objects(wallet1, reqs)
for req in reqs:
assert req.protocolVersion is None

send_signed_requests(client1, reqs)
waitForSufficientRepliesForRequests(looper, client1, requests=reqs)


def test_request_with_correct_version(tconf, looper,
txnPoolNodeSet, client1, client1Connected,
wallet1):
reqs = signed_random_requests(wallet1, 2)
wallet1,
request_num):
reqs = random_request_objects(request_num, protocol_version=CURRENT_PROTOCOL_VERSION)
reqs = sign_request_objects(wallet1, reqs)
for req in reqs:
req.protocolVersion = CURRENT_PROTOCOL_VERSION
assert req.protocolVersion == CURRENT_PROTOCOL_VERSION

send_signed_requests(client1, reqs)
waitForSufficientRepliesForRequests(looper, client1, requests=reqs)


def test_request_with_invalid_version(tconf, looper, txnPoolNodeSet,
client1, client1Connected,
wallet1):
reqs = signed_random_requests(wallet1, 2)
wallet1,
request_num):
reqs = random_request_objects(request_num, protocol_version=-1)
reqs = sign_request_objects(wallet1, reqs)
for req in reqs:
req.protocolVersion = -1
assert req.protocolVersion == -1

send_signed_requests(client1, reqs)
for node in txnPoolNodeSet:
looper.run(eventually(checkReqNackWithReason, client1,
Expand Down
39 changes: 25 additions & 14 deletions plenum/test/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ def sendReqsToNodesAndVerifySuffReplies(looper: Looper,
wallet: Wallet,
client: TestClient,
numReqs: int,
customTimeoutPerReq: float=None,
add_delay_to_timeout: float=0,
customTimeoutPerReq: float = None,
add_delay_to_timeout: float = 0,
override_timeout_limit=False,
total_timeout=None):
requests = sendRandomRequests(wallet, client, numReqs)
Expand All @@ -136,8 +136,8 @@ def send_reqs_to_nodes_and_verify_all_replies(looper: Looper,
wallet: Wallet,
client: TestClient,
numReqs: int,
customTimeoutPerReq: float=None,
add_delay_to_timeout: float=0,
customTimeoutPerReq: float = None,
add_delay_to_timeout: float = 0,
override_timeout_limit=False,
total_timeout=None):
requests = sendRandomRequests(wallet, client, numReqs)
Expand Down Expand Up @@ -308,13 +308,24 @@ def randomOperation():
def random_requests(count):
return [{
"type": "buy",
"amount": random.randint(10, 100)
"amount": random.randint(10, 100)
} for _ in range(count)]


def random_request_objects(count, protocol_version):
req_dicts = random_requests(count)
return [Request(operation=op, protocolVersion=protocol_version) for op in req_dicts]

def sign_request_objects(wallet, reqs: Sequence):
return [wallet.signRequest(req) for req in reqs]

def sign_requests(wallet, reqs: Sequence):
return [wallet.signOp(req) for req in reqs]


def signed_random_requests(wallet, count):
reqs = random_requests(count)
return [wallet.signOp(req) for req in reqs]
return sign_requests(wallet, reqs)


def send_signed_requests(client: Client, signed_reqs: Sequence):
Expand Down Expand Up @@ -347,7 +358,7 @@ async def msgAll(nodes: TestNodeSet):
def sendMessage(nodes: TestNodeSet,
frm: NodeRef,
to: NodeRef,
msg: Optional[Tuple]=None):
msg: Optional[Tuple] = None):
"""
Sends message from one node to another
Expand Down Expand Up @@ -398,7 +409,7 @@ async def sendMessageAndCheckDelivery(nodes: TestNodeSet,

def sendMessageToAll(nodes: TestNodeSet,
frm: NodeRef,
msg: Optional[Tuple]=None):
msg: Optional[Tuple] = None):
"""
Sends message from one node to all others
Expand All @@ -414,7 +425,7 @@ def sendMessageToAll(nodes: TestNodeSet,

async def sendMessageAndCheckDeliveryToAll(nodes: TestNodeSet,
frm: NodeRef,
msg: Optional[Tuple]=None,
msg: Optional[Tuple] = None,
method=None,
customTimeout=None):
"""
Expand Down Expand Up @@ -688,11 +699,11 @@ def countDiscarded(processor, reasonPat):
c = 0
for entry in processor.spylog.getAll(processor.discard):
if 'reason' in entry.params and (
(isinstance(
entry.params['reason'],
str) and reasonPat in entry.params['reason']),
(isinstance(
entry.params['reason'],
str) and reasonPat in entry.params['reason']),
(reasonPat in str(
entry.params['reason']))):
entry.params['reason']))):
c += 1
return c

Expand Down Expand Up @@ -745,7 +756,7 @@ def checkStateEquality(state1, state2):


def check_seqno_db_equality(db1, db2):
assert db1.size == db2.size,\
assert db1.size == db2.size, \
"{} != {}".format(db1.size, db2.size)
assert {bytes(k): bytes(v) for k, v in db1._keyValueStorage.iterator()} == \
{bytes(k): bytes(v) for k, v in db2._keyValueStorage.iterator()}
Expand Down
13 changes: 10 additions & 3 deletions plenum/test/input_validation/test_client_safe_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ def test_minimal_valid(operation):
operation=operation)


def test_no_version_by_default(operation):
req = SafeRequest(identifier="1" * 16,
reqId=1,
operation=operation)
assert not req.protocolVersion


def test_with_signature_valid(operation):
assert SafeRequest(identifier="1" * 16,
reqId=1,
Expand All @@ -47,9 +54,9 @@ def test_with_version_valid(operation):

def test_no_version_valid(operation):
safeReq = SafeRequest(identifier="1" * 16,
reqId=1,
operation=operation,
protocolVersion=None)
reqId=1,
operation=operation,
protocolVersion=None)
assert safeReq
assert not safeReq.protocolVersion

Expand Down
Loading