Skip to content

Commit 2b25500

Browse files
authored
Merge pull request #1574 from jannikluhn/bcc-requests
Beacon block request handler
2 parents 7e3b313 + f6681fc commit 2b25500

File tree

9 files changed

+581
-175
lines changed

9 files changed

+581
-175
lines changed

tests/trinity/core/p2p-proto/bcc/__init__.py

Whitespace-only changes.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import asyncio
2+
3+
from cancel_token import CancelToken
4+
5+
from eth_utils import (
6+
to_tuple,
7+
)
8+
from eth_utils.toolz import (
9+
merge,
10+
)
11+
12+
from eth.db.atomic import AtomicDB
13+
from eth.beacon.db.chain import BeaconChainDB
14+
from eth.beacon.types.blocks import BaseBeaconBlock
15+
from eth.constants import (
16+
ZERO_HASH32,
17+
)
18+
19+
from trinity.protocol.bcc.context import BeaconContext
20+
from trinity.protocol.bcc.peer import (
21+
BCCPeerFactory,
22+
BCCPeerPool,
23+
)
24+
25+
from p2p import ecies
26+
from p2p.tools.paragon.helpers import (
27+
get_directly_linked_peers_without_handshake as _get_directly_linked_peers_without_handshake,
28+
get_directly_linked_peers as _get_directly_linked_peers,
29+
)
30+
31+
32+
def create_test_block(parent=None, **kwargs):
33+
defaults = {
34+
"slot": 0,
35+
"randao_reveal": ZERO_HASH32,
36+
"candidate_pow_receipt_root": ZERO_HASH32,
37+
"ancestor_hashes": [ZERO_HASH32] * 32,
38+
"state_root": ZERO_HASH32, # note: not the actual genesis state root
39+
"attestations": [],
40+
"specials": [],
41+
"proposer_signature": None,
42+
}
43+
44+
if parent is not None:
45+
kwargs["ancestor_hashes"] = [parent.hash] + [ZERO_HASH32] * 31
46+
kwargs["slot"] = parent.slot + 1
47+
48+
return BaseBeaconBlock(**merge(defaults, kwargs))
49+
50+
51+
@to_tuple
52+
def create_branch(length, root, **start_kwargs):
53+
if length == 0:
54+
return
55+
56+
parent = create_test_block(parent=root, **start_kwargs)
57+
yield parent
58+
59+
for slot in range(root.slot + 2, root.slot + length + 1):
60+
child = create_test_block(parent)
61+
yield child
62+
parent = child
63+
64+
65+
def get_fresh_chain_db():
66+
db = AtomicDB()
67+
genesis_block = create_test_block(slot=0)
68+
69+
chain_db = BeaconChainDB(db)
70+
chain_db.persist_block(genesis_block)
71+
72+
return chain_db
73+
74+
75+
async def _setup_alice_and_bob_factories(alice_chain_db=None, bob_chain_db=None):
76+
cancel_token = CancelToken('trinity.get_directly_linked_peers_without_handshake')
77+
78+
#
79+
# Alice
80+
#
81+
if alice_chain_db is None:
82+
alice_chain_db = get_fresh_chain_db()
83+
84+
alice_context = BeaconContext(
85+
chain_db=alice_chain_db,
86+
network_id=1,
87+
)
88+
89+
alice_factory = BCCPeerFactory(
90+
privkey=ecies.generate_privkey(),
91+
context=alice_context,
92+
token=cancel_token,
93+
)
94+
95+
#
96+
# Bob
97+
#
98+
if bob_chain_db is None:
99+
bob_chain_db = get_fresh_chain_db()
100+
101+
bob_context = BeaconContext(
102+
chain_db=bob_chain_db,
103+
network_id=1,
104+
)
105+
106+
bob_factory = BCCPeerFactory(
107+
privkey=ecies.generate_privkey(),
108+
context=bob_context,
109+
token=cancel_token,
110+
)
111+
112+
return alice_factory, bob_factory
113+
114+
115+
async def get_directly_linked_peers_without_handshake(alice_chain_db=None, bob_chain_db=None):
116+
alice_factory, bob_factory = await _setup_alice_and_bob_factories(alice_chain_db, bob_chain_db)
117+
118+
return await _get_directly_linked_peers_without_handshake(
119+
alice_factory=alice_factory,
120+
bob_factory=bob_factory,
121+
)
122+
123+
124+
async def get_directly_linked_peers(request, event_loop, alice_chain_db=None, bob_chain_db=None):
125+
alice_factory, bob_factory = await _setup_alice_and_bob_factories(
126+
alice_chain_db,
127+
bob_chain_db,
128+
)
129+
130+
return await _get_directly_linked_peers(
131+
request,
132+
event_loop,
133+
alice_factory=alice_factory,
134+
bob_factory=bob_factory,
135+
)
136+
137+
138+
async def get_directly_linked_peers_in_peer_pools(request, event_loop, chain_db=None):
139+
alice, bob = await get_directly_linked_peers(request, event_loop, bob_chain_db=chain_db)
140+
alice_peer_pool = BCCPeerPool(alice.privkey, alice.context)
141+
bob_peer_pool = BCCPeerPool(bob.privkey, bob.context)
142+
143+
asyncio.ensure_future(alice_peer_pool.run())
144+
asyncio.ensure_future(bob_peer_pool.run())
145+
146+
def finalizer():
147+
event_loop.run_until_complete(alice_peer_pool.cancel())
148+
event_loop.run_until_complete(bob_peer_pool.cancel())
149+
150+
request.addfinalizer(finalizer)
151+
152+
alice_peer_pool._add_peer(alice, [])
153+
bob_peer_pool._add_peer(bob, [])
154+
155+
return alice, alice_peer_pool, bob, bob_peer_pool

tests/trinity/core/p2p-proto/test_bcc.py renamed to tests/trinity/core/p2p-proto/bcc/test_commands.py

Lines changed: 6 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,28 @@
11
import pytest
22

3-
import asyncio
4-
5-
from cancel_token import CancelToken
6-
73
from eth.beacon.types.attestation_records import AttestationRecord
84
from eth.beacon.types.attestation_data import AttestationData
9-
from eth.db.atomic import AtomicDB
10-
from eth.beacon.db.chain import BeaconChainDB
115
from eth.beacon.types.blocks import BaseBeaconBlock
126

137
from eth.constants import (
148
ZERO_HASH32,
159
)
1610

17-
from p2p import ecies
18-
from p2p.exceptions import HandshakeFailure
19-
from p2p.peer import MsgBuffer
20-
21-
from trinity.protocol.bcc.context import BeaconContext
22-
from trinity.protocol.bcc.peer import (
23-
BCCPeerFactory,
11+
from p2p.peer import (
12+
MsgBuffer,
2413
)
25-
from trinity.protocol.bcc.proto import BCCProtocol
14+
2615
from trinity.protocol.bcc.commands import (
27-
Status,
28-
GetBeaconBlocks,
2916
BeaconBlocks,
17+
GetBeaconBlocks,
3018
AttestationRecords,
3119
)
3220

33-
from p2p.tools.paragon.helpers import (
34-
get_directly_linked_peers_without_handshake as _get_directly_linked_peers_without_handshake,
35-
get_directly_linked_peers as _get_directly_linked_peers,
21+
from .helpers import (
22+
get_directly_linked_peers,
3623
)
3724

3825

39-
def get_fresh_chain_db():
40-
db = AtomicDB()
41-
genesis_block = BaseBeaconBlock(
42-
slot=0,
43-
randao_reveal=ZERO_HASH32,
44-
candidate_pow_receipt_root=ZERO_HASH32,
45-
ancestor_hashes=[ZERO_HASH32] * 32,
46-
state_root=ZERO_HASH32, # note: not the actual genesis state root
47-
attestations=[],
48-
specials=[],
49-
proposer_signature=None,
50-
)
51-
52-
chain_db = BeaconChainDB(db)
53-
chain_db.persist_block(genesis_block)
54-
return chain_db
55-
56-
57-
async def _setup_alice_and_bob_factories(alice_chain_db=None, bob_chain_db=None):
58-
cancel_token = CancelToken('trinity.get_directly_linked_peers_without_handshake')
59-
60-
#
61-
# Alice
62-
#
63-
if alice_chain_db is None:
64-
alice_chain_db = get_fresh_chain_db()
65-
66-
alice_context = BeaconContext(
67-
chain_db=alice_chain_db,
68-
network_id=1,
69-
)
70-
71-
alice_factory = BCCPeerFactory(
72-
privkey=ecies.generate_privkey(),
73-
context=alice_context,
74-
token=cancel_token,
75-
)
76-
77-
#
78-
# Bob
79-
#
80-
if bob_chain_db is None:
81-
bob_chain_db = get_fresh_chain_db()
82-
83-
bob_context = BeaconContext(
84-
chain_db=bob_chain_db,
85-
network_id=1,
86-
)
87-
88-
bob_factory = BCCPeerFactory(
89-
privkey=ecies.generate_privkey(),
90-
context=bob_context,
91-
token=cancel_token,
92-
)
93-
94-
return alice_factory, bob_factory
95-
96-
97-
async def get_directly_linked_peers_without_handshake(alice_chain_db=None, bob_chain_db=None):
98-
alice_factory, bob_factory = await _setup_alice_and_bob_factories(alice_chain_db, bob_chain_db)
99-
100-
return await _get_directly_linked_peers_without_handshake(
101-
alice_factory=alice_factory,
102-
bob_factory=bob_factory,
103-
)
104-
105-
106-
async def get_directly_linked_peers(request, event_loop, alice_chain_db=None, bob_chain_db=None):
107-
alice_factory, bob_factory = await _setup_alice_and_bob_factories(
108-
alice_chain_db,
109-
bob_chain_db,
110-
)
111-
112-
return await _get_directly_linked_peers(
113-
request,
114-
event_loop,
115-
alice_factory=alice_factory,
116-
bob_factory=bob_factory,
117-
)
118-
119-
120-
@pytest.mark.asyncio
121-
async def test_directly_linked_peers_without_handshake():
122-
alice, bob = await get_directly_linked_peers_without_handshake()
123-
assert alice.sub_proto is None
124-
assert bob.sub_proto is None
125-
126-
127-
@pytest.mark.asyncio
128-
async def test_directly_linked_peers(request, event_loop):
129-
alice, bob = await get_directly_linked_peers(request, event_loop)
130-
assert isinstance(alice.sub_proto, BCCProtocol)
131-
assert isinstance(bob.sub_proto, BCCProtocol)
132-
133-
assert alice.head_hash == bob.context.chain_db.get_canonical_head().hash
134-
assert bob.head_hash == alice.context.chain_db.get_canonical_head().hash
135-
136-
137-
@pytest.mark.asyncio
138-
async def test_unidirectional_handshake(request, event_loop):
139-
alice, bob = await get_directly_linked_peers_without_handshake()
140-
alice_chain_db = alice.context.chain_db
141-
alice_genesis_hash = alice_chain_db.get_canonical_block_by_slot(0).hash
142-
alice_head_hash = alice_chain_db.get_canonical_head().hash
143-
144-
await asyncio.gather(alice.do_p2p_handshake(), bob.do_p2p_handshake())
145-
146-
await alice.send_sub_proto_handshake()
147-
cmd, msg = await bob.read_msg()
148-
149-
assert isinstance(cmd, Status)
150-
151-
assert msg["protocol_version"] == BCCProtocol.version
152-
assert msg["network_id"] == alice.context.network_id
153-
assert msg["genesis_hash"] == alice_head_hash
154-
assert msg["best_hash"] == alice_genesis_hash
155-
156-
await bob.process_sub_proto_handshake(cmd, msg)
157-
158-
assert bob.head_hash == alice_head_hash
159-
assert alice.head_hash is None
160-
161-
# stop cleanly
162-
asyncio.ensure_future(alice.run())
163-
asyncio.ensure_future(bob.run())
164-
await asyncio.gather(
165-
alice.cancel(),
166-
bob.cancel(),
167-
)
168-
169-
170-
@pytest.mark.asyncio
171-
async def test_handshake_wrong_network_id(request, event_loop):
172-
alice, bob = await get_directly_linked_peers_without_handshake()
173-
alice.context.network_id += 1
174-
await asyncio.gather(alice.do_p2p_handshake(), bob.do_p2p_handshake())
175-
176-
await alice.send_sub_proto_handshake()
177-
cmd, msg = await bob.read_msg()
178-
179-
with pytest.raises(HandshakeFailure):
180-
await bob.process_sub_proto_handshake(cmd, msg)
181-
182-
# stop cleanly
183-
asyncio.ensure_future(alice.run())
184-
asyncio.ensure_future(bob.run())
185-
await asyncio.gather(
186-
alice.cancel(),
187-
bob.cancel(),
188-
)
189-
190-
19126
@pytest.mark.asyncio
19227
async def test_send_no_blocks(request, event_loop):
19328
alice, bob = await get_directly_linked_peers(request, event_loop)

0 commit comments

Comments
 (0)