Skip to content

Commit 6ee8275

Browse files
authored
Merge pull request #59 from hyperledger/master
Master
2 parents 441580d + 0ba6a87 commit 6ee8275

13 files changed

+158
-52
lines changed

ci/code-validation.dockerfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ FROM ubuntu:16.04
44
ARG uid=1000
55

66
# Install environment
7-
RUN apt-get update -y
8-
RUN apt-get install -y \
7+
RUN apt-get update -y && apt-get install -y \
98
git \
109
wget \
1110
python3.5 \

plenum/client/client.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ def __init__(self,
192192
logger.debug("total plugins loaded in client: {}".format(tp))
193193

194194
self._multi_sig_verifier = self._create_multi_sig_verifier()
195+
self._read_only_requests = set()
195196

196197
@lazy_field
197198
def _bls_register(self):
@@ -276,11 +277,14 @@ async def prod(self, limit) -> int:
276277
def submitReqs(self, *reqs: Request) -> List[Request]:
277278
requests = []
278279
errs = []
280+
279281
for request in reqs:
280-
if (self.mode == Mode.discovered and self.hasSufficientConnections) or (
281-
request.isForced() and self.hasAnyConnections):
282-
logger.debug(
283-
'Client {} sending request {}'.format(self, request))
282+
if (self.mode == Mode.discovered and self.hasSufficientConnections) or \
283+
(self.hasAnyConnections and
284+
(request.txn_type in self._read_only_requests or request.isForced())):
285+
286+
logger.debug('Client {} sending request {}'
287+
.format(self, request))
284288
stat, err_msg = self.send(request)
285289
if stat:
286290
self.expectingFor(request)
@@ -292,7 +296,7 @@ def submitReqs(self, *reqs: Request) -> List[Request]:
292296
else:
293297
logger.debug(
294298
"{} pending request since in mode {} and "
295-
"connected to {} nodes". format(
299+
"connected to {} nodes".format(
296300
self, self.mode, self.nodestack.connecteds))
297301
self.pendReqsTillConnection(request)
298302
requests.append(request)

plenum/client/wallet.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from jsonpickle.util import importable_name
1212
from libnacl import crypto_secretbox_open, randombytes, \
1313
crypto_secretbox_NONCEBYTES, crypto_secretbox
14+
from plenum.common.constants import CURRENT_PROTOCOL_VERSION
1415

1516
from plenum.common.did_method import DidMethods, DefaultDidMethods
1617
from plenum.common.exceptions import EmptyIdentifier
@@ -226,7 +227,7 @@ def signOp(self,
226227
:param op: Operation to be signed
227228
:return: a signed Request object
228229
"""
229-
request = Request(operation=op)
230+
request = Request(operation=op, protocolVersion=CURRENT_PROTOCOL_VERSION)
230231
return self.signRequest(request, identifier)
231232

232233
def _signerById(self, idr: Identifier):

plenum/common/request.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Mapping, NamedTuple
33

44
from common.serializers.serialization import serialize_msg_for_signing
5-
from plenum.common.constants import REQDIGEST, REQKEY, FORCE, CURRENT_PROTOCOL_VERSION
5+
from plenum.common.constants import REQDIGEST, REQKEY, FORCE, TXN_TYPE
66
from plenum.common.messages.client_request import ClientMessageValidator
77
from plenum.common.types import f, OPERATION
88
from stp_core.types import Identifier
@@ -14,7 +14,7 @@ def __init__(self,
1414
reqId: int = None,
1515
operation: Mapping = None,
1616
signature: str = None,
17-
protocolVersion: int = CURRENT_PROTOCOL_VERSION):
17+
protocolVersion: int = None):
1818
self.identifier = identifier
1919
self.reqId = reqId
2020
self.operation = operation
@@ -87,6 +87,10 @@ def isForced(self):
8787
force = self.operation.get(FORCE)
8888
return str(force) == 'True'
8989

90+
@property
91+
def txn_type(self):
92+
return self.operation.get(TXN_TYPE)
93+
9094
def __hash__(self):
9195
return hash(self.serialized())
9296

plenum/test/cli/helper.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import plenum.cli.cli as cli
1212
from plenum.client.wallet import Wallet
13-
from plenum.common.constants import PRIMARY_SELECTION_PREFIX
13+
from plenum.common.constants import PRIMARY_SELECTION_PREFIX, CURRENT_PROTOCOL_VERSION
1414
from stp_core.common.constants import CONNECTION_PREFIX
1515
from stp_core.common.util import Singleton
1616
from stp_core.loop.eventually import eventually
@@ -275,7 +275,8 @@ def checkRequest(cli, operation):
275275
lastReqId = wallet._getIdData().lastReqId
276276

277277
request = Request(identifier=wallet.defaultId,
278-
reqId=lastReqId)
278+
reqId=lastReqId,
279+
protocolVersion=CURRENT_PROTOCOL_VERSION)
279280

280281
waitForSufficientRepliesForRequests(cli.looper, client,
281282
requests=[request])

plenum/test/cli/test_log_filtering.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import types
22

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

2223
request = Request(identifier=wallet.defaultId,
23-
reqId=wallet._getIdData().lastReqId)
24+
reqId=wallet._getIdData().lastReqId,
25+
protocolVersion=CURRENT_PROTOCOL_VERSION)
2426

2527
waitForSufficientRepliesForRequests(cli.looper, client,
2628
requests=[request])
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import random
2+
3+
from plenum.test.client.conftest import passThroughReqAcked1
4+
5+
from plenum.test.helper import sendReqsToNodesAndVerifySuffReplies, stopNodes, waitForSufficientRepliesForRequests, \
6+
send_signed_requests
7+
from plenum.test.malicious_behaviors_client import \
8+
genDoesntSendRequestToSomeNodes
9+
from plenum.test.node_catchup.helper import waitNodeDataEquality
10+
11+
12+
nodeCount = 4
13+
clientFault = genDoesntSendRequestToSomeNodes("AlphaC")
14+
reqAcked1 = passThroughReqAcked1
15+
16+
17+
def test_client_sends_get_request_to_one_node(looper,
18+
client1,
19+
wallet1,
20+
nodeSet):
21+
"""
22+
Check that read only equest can be sent
23+
without having connection to all nodes
24+
"""
25+
client = client1
26+
wallet = wallet1
27+
28+
nodes_to_stop = list(nodeSet)[1:]
29+
stopNodes(nodes_to_stop, looper)
30+
31+
initial_submit_count = client.spylog.count(client.submitReqs)
32+
initial_send_count = client.spylog.count(client.send)
33+
34+
def sign_and_send(op):
35+
signed = wallet.signOp(op)
36+
send_signed_requests(client, [signed])
37+
38+
buy = {'type': 'buy', 'amount': random.randint(10, 100)}
39+
sign_and_send(buy)
40+
assert initial_submit_count + 1 == client.spylog.count(client.submitReqs)
41+
assert initial_send_count == client.spylog.count(client.send)
42+
43+
get_buy = {'type': 'get_buy'}
44+
client._read_only_requests.add('get_buy')
45+
sign_and_send(get_buy)
46+
assert initial_submit_count + 2 == client.spylog.count(client.submitReqs)
47+
assert initial_send_count + 1 == client.spylog.count(client.send)

plenum/test/client/test_protocol_version.py

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,69 @@
1+
import pytest
12
from plenum.common.constants import CURRENT_PROTOCOL_VERSION
2-
from plenum.test.helper import sendRandomRequests, waitForSufficientRepliesForRequests, signed_random_requests, \
3-
send_signed_requests, checkReqNackWithReason
3+
from plenum.common.request import Request
4+
from plenum.test.helper import waitForSufficientRepliesForRequests, \
5+
send_signed_requests, checkReqNackWithReason, random_request_objects, \
6+
sign_request_objects, signed_random_requests, random_requests
47
from plenum.test.pool_transactions.conftest import looper, clientAndWallet1, \
58
client1, wallet1, client1Connected
69
from stp_core.loop.eventually import eventually
710

811

12+
@pytest.yield_fixture(scope="function", params=['1', '2'])
13+
def request_num(request):
14+
return int(request.param)
15+
916
def test_request_no_protocol_version(tconf, looper, txnPoolNodeSet,
1017
client1, client1Connected,
11-
wallet1):
12-
reqs = signed_random_requests(wallet1, 2)
18+
wallet1,
19+
request_num):
20+
reqs = random_request_objects(request_num, protocol_version=None)
21+
reqs = sign_request_objects(wallet1, reqs)
1322
for req in reqs:
14-
req.protocolVersion = None
23+
assert req.protocolVersion is None
24+
1525
send_signed_requests(client1, reqs)
1626
waitForSufficientRepliesForRequests(looper, client1, requests=reqs)
1727

1828

19-
def test_version_set_by_default(tconf, looper, txnPoolNodeSet,
29+
def test_version_not_set_by_default(tconf, looper, txnPoolNodeSet,
2030
client1, client1Connected,
21-
wallet1):
22-
reqs = signed_random_requests(wallet1, 1)
23-
assert reqs[0].protocolVersion
31+
wallet1,
32+
request_num):
33+
req_dicts = random_requests(request_num)
34+
reqs = [Request(operation=op) for op in req_dicts]
35+
for req in reqs:
36+
assert req.protocolVersion is None
37+
reqs = sign_request_objects(wallet1, reqs)
38+
for req in reqs:
39+
assert req.protocolVersion is None
40+
2441
send_signed_requests(client1, reqs)
2542
waitForSufficientRepliesForRequests(looper, client1, requests=reqs)
2643

2744

2845
def test_request_with_correct_version(tconf, looper,
2946
txnPoolNodeSet, client1, client1Connected,
30-
wallet1):
31-
reqs = signed_random_requests(wallet1, 2)
47+
wallet1,
48+
request_num):
49+
reqs = random_request_objects(request_num, protocol_version=CURRENT_PROTOCOL_VERSION)
50+
reqs = sign_request_objects(wallet1, reqs)
3251
for req in reqs:
33-
req.protocolVersion = CURRENT_PROTOCOL_VERSION
52+
assert req.protocolVersion == CURRENT_PROTOCOL_VERSION
53+
3454
send_signed_requests(client1, reqs)
3555
waitForSufficientRepliesForRequests(looper, client1, requests=reqs)
3656

3757

3858
def test_request_with_invalid_version(tconf, looper, txnPoolNodeSet,
3959
client1, client1Connected,
40-
wallet1):
41-
reqs = signed_random_requests(wallet1, 2)
60+
wallet1,
61+
request_num):
62+
reqs = random_request_objects(request_num, protocol_version=-1)
63+
reqs = sign_request_objects(wallet1, reqs)
4264
for req in reqs:
43-
req.protocolVersion = -1
65+
assert req.protocolVersion == -1
66+
4467
send_signed_requests(client1, reqs)
4568
for node in txnPoolNodeSet:
4669
looper.run(eventually(checkReqNackWithReason, client1,

plenum/test/helper.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ def sendReqsToNodesAndVerifySuffReplies(looper: Looper,
116116
wallet: Wallet,
117117
client: TestClient,
118118
numReqs: int,
119-
customTimeoutPerReq: float=None,
120-
add_delay_to_timeout: float=0,
119+
customTimeoutPerReq: float = None,
120+
add_delay_to_timeout: float = 0,
121121
override_timeout_limit=False,
122122
total_timeout=None):
123123
requests = sendRandomRequests(wallet, client, numReqs)
@@ -136,8 +136,8 @@ def send_reqs_to_nodes_and_verify_all_replies(looper: Looper,
136136
wallet: Wallet,
137137
client: TestClient,
138138
numReqs: int,
139-
customTimeoutPerReq: float=None,
140-
add_delay_to_timeout: float=0,
139+
customTimeoutPerReq: float = None,
140+
add_delay_to_timeout: float = 0,
141141
override_timeout_limit=False,
142142
total_timeout=None):
143143
requests = sendRandomRequests(wallet, client, numReqs)
@@ -308,13 +308,24 @@ def randomOperation():
308308
def random_requests(count):
309309
return [{
310310
"type": "buy",
311-
"amount": random.randint(10, 100)
311+
"amount": random.randint(10, 100)
312312
} for _ in range(count)]
313313

314314

315+
def random_request_objects(count, protocol_version):
316+
req_dicts = random_requests(count)
317+
return [Request(operation=op, protocolVersion=protocol_version) for op in req_dicts]
318+
319+
def sign_request_objects(wallet, reqs: Sequence):
320+
return [wallet.signRequest(req) for req in reqs]
321+
322+
def sign_requests(wallet, reqs: Sequence):
323+
return [wallet.signOp(req) for req in reqs]
324+
325+
315326
def signed_random_requests(wallet, count):
316327
reqs = random_requests(count)
317-
return [wallet.signOp(req) for req in reqs]
328+
return sign_requests(wallet, reqs)
318329

319330

320331
def send_signed_requests(client: Client, signed_reqs: Sequence):
@@ -347,7 +358,7 @@ async def msgAll(nodes: TestNodeSet):
347358
def sendMessage(nodes: TestNodeSet,
348359
frm: NodeRef,
349360
to: NodeRef,
350-
msg: Optional[Tuple]=None):
361+
msg: Optional[Tuple] = None):
351362
"""
352363
Sends message from one node to another
353364
@@ -398,7 +409,7 @@ async def sendMessageAndCheckDelivery(nodes: TestNodeSet,
398409

399410
def sendMessageToAll(nodes: TestNodeSet,
400411
frm: NodeRef,
401-
msg: Optional[Tuple]=None):
412+
msg: Optional[Tuple] = None):
402413
"""
403414
Sends message from one node to all others
404415
@@ -414,7 +425,7 @@ def sendMessageToAll(nodes: TestNodeSet,
414425

415426
async def sendMessageAndCheckDeliveryToAll(nodes: TestNodeSet,
416427
frm: NodeRef,
417-
msg: Optional[Tuple]=None,
428+
msg: Optional[Tuple] = None,
418429
method=None,
419430
customTimeout=None):
420431
"""
@@ -688,11 +699,11 @@ def countDiscarded(processor, reasonPat):
688699
c = 0
689700
for entry in processor.spylog.getAll(processor.discard):
690701
if 'reason' in entry.params and (
691-
(isinstance(
692-
entry.params['reason'],
693-
str) and reasonPat in entry.params['reason']),
702+
(isinstance(
703+
entry.params['reason'],
704+
str) and reasonPat in entry.params['reason']),
694705
(reasonPat in str(
695-
entry.params['reason']))):
706+
entry.params['reason']))):
696707
c += 1
697708
return c
698709

@@ -745,7 +756,7 @@ def checkStateEquality(state1, state2):
745756

746757

747758
def check_seqno_db_equality(db1, db2):
748-
assert db1.size == db2.size,\
759+
assert db1.size == db2.size, \
749760
"{} != {}".format(db1.size, db2.size)
750761
assert {bytes(k): bytes(v) for k, v in db1._keyValueStorage.iterator()} == \
751762
{bytes(k): bytes(v) for k, v in db2._keyValueStorage.iterator()}

plenum/test/input_validation/test_client_safe_request.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ def test_minimal_valid(operation):
3131
operation=operation)
3232

3333

34+
def test_no_version_by_default(operation):
35+
req = SafeRequest(identifier="1" * 16,
36+
reqId=1,
37+
operation=operation)
38+
assert not req.protocolVersion
39+
40+
3441
def test_with_signature_valid(operation):
3542
assert SafeRequest(identifier="1" * 16,
3643
reqId=1,
@@ -47,9 +54,9 @@ def test_with_version_valid(operation):
4754

4855
def test_no_version_valid(operation):
4956
safeReq = SafeRequest(identifier="1" * 16,
50-
reqId=1,
51-
operation=operation,
52-
protocolVersion=None)
57+
reqId=1,
58+
operation=operation,
59+
protocolVersion=None)
5360
assert safeReq
5461
assert not safeReq.protocolVersion
5562

0 commit comments

Comments
 (0)