Reduce the use of locks with synchronous store methods

This commit is contained in:
Mariano Sorgente 2020-01-28 17:14:50 +09:00
parent 194285f6d4
commit 6f45a4d515
No known key found for this signature in database
GPG Key ID: 0F866338C369278C
5 changed files with 212 additions and 239 deletions

View File

@ -70,7 +70,6 @@ class ClassGroup(tuple):
for x in [r[0], r[1]]])
def __eq__(self, other):
print("other", other)
return tuple(self.reduced()) == tuple(ClassGroup((other[0], other[1], other[2])).reduced())
def __ne__(self, other):

View File

@ -101,27 +101,24 @@ class FullNode:
"""
challenge_requests: List[timelord_protocol.ChallengeStart] = []
pos_info_requests: List[timelord_protocol.ProofOfSpaceInfo] = []
async with self.store.lock:
tips: List[SmallHeaderBlock] = self.blockchain.get_current_tips()
for tip in tips:
assert tip.challenge
challenge_hash = tip.challenge.get_hash()
challenge_requests.append(
timelord_protocol.ChallengeStart(
challenge_hash, tip.challenge.total_weight
)
tips: List[SmallHeaderBlock] = self.blockchain.get_current_tips()
for tip in tips:
assert tip.challenge
challenge_hash = tip.challenge.get_hash()
challenge_requests.append(
timelord_protocol.ChallengeStart(
challenge_hash, tip.challenge.total_weight
)
)
tip_hashes = [tip.header_hash for tip in tips]
tip_infos = [
tup[0]
for tup in list((await self.store.get_unfinished_blocks()).items())
if tup[1].prev_header_hash in tip_hashes
]
for chall, iters in tip_infos:
pos_info_requests.append(
timelord_protocol.ProofOfSpaceInfo(chall, iters)
)
tip_hashes = [tip.header_hash for tip in tips]
tip_infos = [
tup[0]
for tup in list((self.store.get_unfinished_blocks()).items())
if tup[1].prev_header_hash in tip_hashes
]
for chall, iters in tip_infos:
pos_info_requests.append(timelord_protocol.ProofOfSpaceInfo(chall, iters))
for challenge_msg in challenge_requests:
yield OutboundMessage(
NodeType.TIMELORD, Message("challenge_start", challenge_msg), delivery
@ -214,30 +211,24 @@ class FullNode:
# Based on responses from peers about the current heads, see which head is the heaviest
# (similar to longest chain rule).
async with self.store.lock:
potential_tips: List[
Tuple[bytes32, FullBlock]
] = await self.store.get_potential_tips_tuples()
log.info(f"Have collected {len(potential_tips)} potential tips")
for header_hash, potential_tip_block in potential_tips:
if potential_tip_block.header_block.challenge is None:
raise ValueError(
f"Invalid tip block {potential_tip_block.header_hash} received"
)
if (
potential_tip_block.header_block.challenge.total_weight
> highest_weight
):
highest_weight = (
potential_tip_block.header_block.challenge.total_weight
)
tip_block = potential_tip_block
tip_height = potential_tip_block.header_block.challenge.height
if highest_weight <= max(
[t.weight for t in self.blockchain.get_current_tips()]
):
log.info("Not performing sync, already caught up.")
return
potential_tips: List[
Tuple[bytes32, FullBlock]
] = self.store.get_potential_tips_tuples()
log.info(f"Have collected {len(potential_tips)} potential tips")
for header_hash, potential_tip_block in potential_tips:
if potential_tip_block.header_block.challenge is None:
raise ValueError(
f"Invalid tip block {potential_tip_block.header_hash} received"
)
if potential_tip_block.header_block.challenge.total_weight > highest_weight:
highest_weight = potential_tip_block.header_block.challenge.total_weight
tip_block = potential_tip_block
tip_height = potential_tip_block.header_block.challenge.height
if highest_weight <= max(
[t.weight for t in self.blockchain.get_current_tips()]
):
log.info("Not performing sync, already caught up.")
return
assert tip_block
log.info(f"Tip block {tip_block.header_hash} tip height {tip_block.height}")
@ -275,10 +266,9 @@ class FullNode:
log.warning("Did not receive desired header hashes")
# Finding the fork point allows us to only download headers and blocks from the fork point
async with self.store.lock:
header_hashes = self.store.get_potential_hashes()
fork_point_height: uint32 = self.blockchain.find_fork_point(header_hashes)
fork_point_hash: bytes32 = header_hashes[fork_point_height]
header_hashes = self.store.get_potential_hashes()
fork_point_height: uint32 = self.blockchain.find_fork_point(header_hashes)
fork_point_hash: bytes32 = header_hashes[fork_point_height]
log.info(f"Fork point: {fork_point_hash} at height {fork_point_height}")
# Now, we download all of the headers in order to verify the weight, in batches
@ -367,11 +357,10 @@ class FullNode:
total_time_slept += sleep_interval
log.info(f"Did not receive desired header blocks")
async with self.store.lock:
for h in range(fork_point_height + 1, tip_height + 1):
header = self.store.get_potential_header(uint32(h))
assert header is not None
headers.append(header)
for h in range(fork_point_height + 1, tip_height + 1):
header = self.store.get_potential_header(uint32(h))
assert header is not None
headers.append(header)
log.info(f"Downloaded headers up to tip height: {tip_height}")
if not verify_weight(
@ -477,7 +466,6 @@ class FullNode:
# Verifies this batch, which we are guaranteed to have (since we broke from the above loop)
blocks = []
# async with self.store.lock:
for height in range(height_checkpoint, end_height):
b: Optional[FullBlock] = await self.store.get_potential_block(
uint32(height)
@ -496,9 +484,9 @@ class FullNode:
)
assert block is not None
prev_block: Optional[
FullBlock
] = await self.store.get_potential_block(uint32(height - 1))
prev_block: Optional[FullBlock] = await self.store.get_potential_block(
uint32(height - 1)
)
if prev_block is None:
prev_block = await self.store.get_block(block.prev_header_hash)
assert prev_block is not None
@ -524,7 +512,7 @@ class FullNode:
max([h.height for h in self.blockchain.get_current_tips()])
>= height
)
await self.store.set_proof_of_time_estimate_ips(
self.store.set_proof_of_time_estimate_ips(
self.blockchain.get_next_ips(block.header_block)
)
log.info(
@ -542,11 +530,10 @@ class FullNode:
Finalize sync by setting sync mode to False, clearing all sync information, and adding any final
blocks that we have finalized recently.
"""
potential_fut_blocks = (self.store.get_potential_future_blocks()).copy()
self.store.set_sync_mode(False)
async with self.store.lock:
potential_fut_blocks = (
await self.store.get_potential_future_blocks()
).copy()
await self.store.set_sync_mode(False)
await self.store.clear_sync_info()
for block in potential_fut_blocks:
@ -579,11 +566,10 @@ class FullNode:
self, all_header_hashes: peer_protocol.AllHeaderHashes
) -> OutboundMessageGenerator:
assert len(all_header_hashes.header_hashes) > 0
async with self.store.lock:
self.store.set_potential_hashes(all_header_hashes.header_hashes)
phr = self.store.get_potential_hashes_received()
assert phr is not None
phr.set()
self.store.set_potential_hashes(all_header_hashes.header_hashes)
phr = self.store.get_potential_hashes_received()
assert phr is not None
phr.set()
for _ in []: # Yields nothing
yield _
@ -632,10 +618,9 @@ class FullNode:
log.info(
f"Received header blocks {request.header_blocks[0].height, request.header_blocks[-1].height}."
)
async with self.store.lock:
for header_block in request.header_blocks:
self.store.add_potential_header(header_block)
(self.store.get_potential_headers_received(header_block.height)).set()
for header_block in request.header_blocks:
self.store.add_potential_header(header_block)
(self.store.get_potential_headers_received(header_block.height)).set()
for _ in []: # Yields nothing
yield _
@ -668,9 +653,7 @@ class FullNode:
HeaderBlock
] = await self.store.get_header_blocks_by_hash(header_hashes)
for header_block in header_blocks:
fetched = await self.store.get_block(
header_block.header.get_hash()
)
fetched = await self.store.get_block(header_block.header.get_hash())
assert fetched
blocks.append(fetched)
except KeyError:
@ -696,7 +679,7 @@ class FullNode:
We have received the blocks that we needed for syncing. Add them to processing queue.
"""
log.info(f"Received sync blocks {[b.height for b in request.blocks]}")
if not await self.store.get_sync_mode():
if not self.store.get_sync_mode():
log.warning("Receiving sync blocks when we are not in sync mode.")
return
@ -780,7 +763,7 @@ class FullNode:
block_header_data_hash: bytes32 = block_header_data.get_hash()
# self.stores this block so we can submit it to the blockchain after it's signed by harvester
await self.store.add_candidate_block(
self.store.add_candidate_block(
proof_of_space_hash, body, block_header_data, request.proof_of_space
)
@ -800,25 +783,22 @@ class FullNode:
block, which only needs a Proof of Time to be finished. If the signature is valid,
we call the unfinished_block routine.
"""
async with self.store.lock:
candidate: Optional[
Tuple[Body, HeaderData, ProofOfSpace]
] = await self.store.get_candidate_block(header_signature.pos_hash)
if candidate is None:
log.warning(
f"PoS hash {header_signature.pos_hash} not found in database"
)
return
# Verifies that we have the correct header and body self.stored
block_body, block_header_data, pos = candidate
candidate: Optional[
Tuple[Body, HeaderData, ProofOfSpace]
] = self.store.get_candidate_block(header_signature.pos_hash)
if candidate is None:
log.warning(f"PoS hash {header_signature.pos_hash} not found in database")
return
# Verifies that we have the correct header and body self.stored
block_body, block_header_data, pos = candidate
assert block_header_data.get_hash() == header_signature.header_hash
assert block_header_data.get_hash() == header_signature.header_hash
block_header: Header = Header(
block_header_data, header_signature.header_signature
)
header: HeaderBlock = HeaderBlock(pos, None, None, block_header)
unfinished_block_obj: FullBlock = FullBlock(header, block_body)
block_header: Header = Header(
block_header_data, header_signature.header_signature
)
header: HeaderBlock = HeaderBlock(pos, None, None, block_header)
unfinished_block_obj: FullBlock = FullBlock(header, block_body)
# Propagate to ourselves (which validates and does further propagations)
request = peer_protocol.UnfinishedBlock(unfinished_block_obj)
@ -840,9 +820,9 @@ class FullNode:
request.proof.number_of_iterations,
)
unfinished_block_obj: Optional[
FullBlock
] = await self.store.get_unfinished_block(dict_key)
unfinished_block_obj: Optional[FullBlock] = self.store.get_unfinished_block(
dict_key
)
if not unfinished_block_obj:
log.warning(
f"Received a proof of time that we cannot use to complete a block {dict_key}"
@ -879,12 +859,8 @@ class FullNode:
new_header_block, unfinished_block_obj.body
)
async with self.store.lock:
sync_mode = await self.store.get_sync_mode()
if sync_mode:
async with self.store.lock:
await self.store.add_potential_future_block(new_full_block)
if self.store.get_sync_mode():
self.store.add_potential_future_block(new_full_block)
else:
async for msg in self.block(peer_protocol.Block(new_full_block)):
yield msg
@ -900,17 +876,17 @@ class FullNode:
"""
finish_block: bool = False
propagate_proof: bool = False
async with self.store.lock:
if await self.store.get_unfinished_block(
(
new_proof_of_time.proof.challenge_hash,
new_proof_of_time.proof.number_of_iterations,
)
):
if self.store.get_unfinished_block(
(
new_proof_of_time.proof.challenge_hash,
new_proof_of_time.proof.number_of_iterations,
)
):
finish_block = True
elif new_proof_of_time.proof.is_valid(constants["DISCRIMINANT_SIZE_BITS"]):
propagate_proof = True
finish_block = True
elif new_proof_of_time.proof.is_valid(constants["DISCRIMINANT_SIZE_BITS"]):
propagate_proof = True
if finish_block:
request = timelord_protocol.ProofOfTimeFinished(new_proof_of_time.proof)
async for msg in self.proof_of_time_finished(request):
@ -965,13 +941,13 @@ class FullNode:
)
if (
await self.store.get_unfinished_block((challenge_hash, iterations_needed))
self.store.get_unfinished_block((challenge_hash, iterations_needed))
is not None
):
return
expected_time: uint64 = uint64(
int(iterations_needed / (await self.store.get_proof_of_time_estimate_ips()))
int(iterations_needed / (self.store.get_proof_of_time_estimate_ips()))
)
if expected_time > constants["PROPAGATION_DELAY_THRESHOLD"]:
@ -979,37 +955,36 @@ class FullNode:
# If this block is slow, sleep to allow faster blocks to come out first
await asyncio.sleep(5)
async with self.store.lock:
leader: Tuple[uint32, uint64] = self.store.get_unfinished_block_leader()
if leader is None or unfinished_block.block.height > leader[0]:
log.info(
f"This is the first unfinished block at height {unfinished_block.block.height}, so propagate."
)
# If this is the first block we see at this height, propagate
self.store.set_unfinished_block_leader(
(unfinished_block.block.height, expected_time)
)
elif unfinished_block.block.height == leader[0]:
if expected_time > leader[1] + constants["PROPAGATION_THRESHOLD"]:
# If VDF is expected to finish X seconds later than the best, don't propagate
log.info(
f"VDF will finish too late {expected_time} seconds, so don't propagate"
)
return
elif expected_time < leader[1]:
log.info(
f"New best unfinished block at height {unfinished_block.block.height}"
)
# If this will be the first block to finalize, update our leader
self.store.set_unfinished_block_leader((leader[0], expected_time))
else:
# If we have seen an unfinished block at a greater or equal height, don't propagate
log.info(f"Unfinished block at old height, so don't propagate")
return
await self.store.add_unfinished_block(
(challenge_hash, iterations_needed), unfinished_block.block
leader: Tuple[uint32, uint64] = self.store.get_unfinished_block_leader()
if leader is None or unfinished_block.block.height > leader[0]:
log.info(
f"This is the first unfinished block at height {unfinished_block.block.height}, so propagate."
)
# If this is the first block we see at this height, propagate
self.store.set_unfinished_block_leader(
(unfinished_block.block.height, expected_time)
)
elif unfinished_block.block.height == leader[0]:
if expected_time > leader[1] + constants["PROPAGATION_THRESHOLD"]:
# If VDF is expected to finish X seconds later than the best, don't propagate
log.info(
f"VDF will finish too late {expected_time} seconds, so don't propagate"
)
return
elif expected_time < leader[1]:
log.info(
f"New best unfinished block at height {unfinished_block.block.height}"
)
# If this will be the first block to finalize, update our leader
self.store.set_unfinished_block_leader((leader[0], expected_time))
else:
# If we have seen an unfinished block at a greater or equal height, don't propagate
log.info(f"Unfinished block at old height, so don't propagate")
return
self.store.add_unfinished_block(
(challenge_hash, iterations_needed), unfinished_block.block
)
timelord_request = timelord_protocol.ProofOfSpaceInfo(
challenge_hash, iterations_needed
@ -1037,15 +1012,15 @@ class FullNode:
if self.blockchain.cointains_block(header_hash):
return
if self.store.get_sync_mode():
# Add the block to our potential tips list
self.store.add_potential_tip(block.block)
return
prevalidate_block = await self.blockchain.pre_validate_blocks([block.block])
val, pos = prevalidate_block[0]
async with self.store.lock:
if await self.store.get_sync_mode():
# Add the block to our potential tips list
await self.store.add_potential_tip(block.block)
return
prevalidate_block = await self.blockchain.pre_validate_blocks([block.block])
val, pos = prevalidate_block[0]
prev_block: Optional[FullBlock] = await self.store.get_block(
block.block.prev_header_hash
)
@ -1065,6 +1040,7 @@ class FullNode:
or added == ReceiveBlockResult.ADDED_TO_HEAD
):
await self.store.add_block(block.block)
if added == ReceiveBlockResult.ALREADY_HAVE_BLOCK:
return
elif added == ReceiveBlockResult.INVALID_BLOCK:
@ -1074,21 +1050,20 @@ class FullNode:
return
elif added == ReceiveBlockResult.DISCONNECTED_BLOCK:
log.warning(f"Disconnected block {header_hash}")
async with self.store.lock:
tip_height = min(
[head.height for head in self.blockchain.get_current_tips()]
)
tip_height = min(
[head.height for head in self.blockchain.get_current_tips()]
)
if (
block.block.height
> tip_height + self.config["sync_blocks_behind_threshold"]
):
async with self.store.lock:
if await self.store.get_sync_mode():
if self.store.get_sync_mode():
return
await self.store.clear_sync_info()
await self.store.add_potential_tip(block.block)
await self.store.set_sync_mode(True)
self.store.add_potential_tip(block.block)
self.store.set_sync_mode(True)
log.info(
f"We are too far behind this block. Our height is {tip_height} and block is at "
f"{block.block.height}"
@ -1113,27 +1088,22 @@ class FullNode:
"request_block",
peer_protocol.RequestBlock(block.block.prev_header_hash),
)
async with self.store.lock:
await self.store.add_disconnected_block(block.block)
self.store.add_disconnected_block(block.block)
yield OutboundMessage(NodeType.FULL_NODE, msg, Delivery.RESPOND)
return
elif added == ReceiveBlockResult.ADDED_TO_HEAD:
# Only propagate blocks which extend the blockchain (becomes one of the heads)
ips_changed: bool = False
async with self.store.lock:
log.info(
f"Updated heads, new heights: {[b.height for b in self.blockchain.get_current_tips()]}"
)
log.info(
f"Updated heads, new heights: {[b.height for b in self.blockchain.get_current_tips()]}"
)
difficulty = self.blockchain.get_next_difficulty(
block.block.prev_header_hash
)
next_vdf_ips = self.blockchain.get_next_ips(block.block.header_block)
log.info(f"Difficulty {difficulty} IPS {next_vdf_ips}")
if next_vdf_ips != await self.store.get_proof_of_time_estimate_ips():
await self.store.set_proof_of_time_estimate_ips(next_vdf_ips)
ips_changed = True
if ips_changed:
difficulty = self.blockchain.get_next_difficulty(
block.block.prev_header_hash
)
next_vdf_ips = self.blockchain.get_next_ips(block.block.header_block)
log.info(f"Difficulty {difficulty} IPS {next_vdf_ips}")
if next_vdf_ips != self.store.get_proof_of_time_estimate_ips():
self.store.set_proof_of_time_estimate_ips(next_vdf_ips)
rate_update = farmer_protocol.ProofOfTimeRate(next_vdf_ips)
log.info(f"Sending proof of time rate {next_vdf_ips}")
yield OutboundMessage(
@ -1193,21 +1163,20 @@ class FullNode:
# Recursively process the next block if we have it
# This code path is reached if added == ADDED_AS_ORPHAN or ADDED_TO_HEAD
async with self.store.lock:
next_block: Optional[
FullBlock
] = await self.store.get_disconnected_block_by_prev(block.block.header_hash)
next_block: Optional[FullBlock] = self.store.get_disconnected_block_by_prev(
block.block.header_hash
)
if next_block is not None:
async for ret_msg in self.block(peer_protocol.Block(next_block)):
yield ret_msg
async with self.store.lock:
# Removes all temporary data for old blocks
lowest_tip = min(tip.height for tip in self.blockchain.get_current_tips())
clear_height = uint32(max(0, lowest_tip - 30))
await self.store.clear_candidate_blocks_below(clear_height)
await self.store.clear_unfinished_blocks_below(clear_height)
await self.store.clear_disconnected_blocks_below(clear_height)
# Removes all temporary data for old blocks
lowest_tip = min(tip.height for tip in self.blockchain.get_current_tips())
clear_height = uint32(max(0, lowest_tip - 30))
self.store.clear_candidate_blocks_below(clear_height)
self.store.clear_unfinished_blocks_below(clear_height)
self.store.clear_disconnected_blocks_below(clear_height)
@api_request
async def request_block(

View File

@ -56,7 +56,7 @@ class RpcApiHandler:
tips: List[SmallHeaderBlock] = self.full_node.blockchain.get_current_tips()
lca: SmallHeaderBlock = self.full_node.blockchain.lca_block
assert lca.challenge is not None
sync_mode: bool = await self.full_node.store.get_sync_mode()
sync_mode: bool = self.full_node.store.get_sync_mode()
difficulty: uint64 = self.full_node.blockchain.get_next_difficulty(
lca.header_hash
)
@ -176,10 +176,9 @@ class RpcApiHandler:
TODO: remove after transactions and coins are added.
"""
async with self.full_node.store.lock:
ppks: List[
Tuple[uint32, PublicKey]
] = await self.full_node.store.get_pool_pks_hack()
ppks: List[
Tuple[uint32, PublicKey]
] = await self.full_node.store.get_pool_pks_hack()
coin_balances: Dict[str, uint64] = {}
for height, pk in ppks:
@ -201,8 +200,8 @@ class RpcApiHandler:
assert tips[i].challenge is not None
challenge: Challenge = tips[i].challenge # type: ignore
max_tip: SmallHeaderBlock = SmallHeaderBlock(tips[i].header, challenge)
if await self.full_node.store.get_sync_mode():
potential_tips = await self.full_node.store.get_potential_tips_tuples()
if self.full_node.store.get_sync_mode():
potential_tips = self.full_node.store.get_potential_tips_tuples()
for _, pot_block in potential_tips:
if pot_block.weight > max_tip.weight:
assert pot_block.header_block.challenge is not None

View File

@ -191,10 +191,10 @@ class FullNodeStore:
return FullBlock.from_bytes(row[1])
return None
async def add_disconnected_block(self, block: FullBlock) -> None:
def add_disconnected_block(self, block: FullBlock) -> None:
self.disconnected_blocks[block.header_hash] = block
async def get_disconnected_block_by_prev(
def get_disconnected_block_by_prev(
self, prev_header_hash: bytes32
) -> Optional[FullBlock]:
for _, block in self.disconnected_blocks.items():
@ -202,18 +202,18 @@ class FullNodeStore:
return block
return None
async def get_disconnected_block(self, header_hash: bytes32) -> Optional[FullBlock]:
def get_disconnected_block(self, header_hash: bytes32) -> Optional[FullBlock]:
return self.disconnected_blocks.get(header_hash, None)
async def clear_disconnected_blocks_below(self, height: uint32) -> None:
def clear_disconnected_blocks_below(self, height: uint32) -> None:
for key in list(self.disconnected_blocks.keys()):
if self.disconnected_blocks[key].height < height:
del self.disconnected_blocks[key]
async def set_sync_mode(self, sync_mode: bool) -> None:
def set_sync_mode(self, sync_mode: bool) -> None:
self.sync_mode = sync_mode
async def get_sync_mode(self) -> bool:
def get_sync_mode(self) -> bool:
return self.sync_mode
async def clear_sync_info(self):
@ -224,13 +224,13 @@ class FullNodeStore:
self.potential_blocks_received.clear()
self.potential_future_blocks.clear()
async def get_potential_tips_tuples(self) -> List[Tuple[bytes32, FullBlock]]:
def get_potential_tips_tuples(self) -> List[Tuple[bytes32, FullBlock]]:
return list(self.potential_tips.items())
async def add_potential_tip(self, block: FullBlock) -> None:
def add_potential_tip(self, block: FullBlock) -> None:
self.potential_tips[block.header_hash] = block
async def get_potential_tip(self, header_hash: bytes32) -> Optional[FullBlock]:
def get_potential_tip(self, header_hash: bytes32) -> Optional[FullBlock]:
return self.potential_tips.get(header_hash, None)
def add_potential_header(self, block: HeaderBlock) -> None:
@ -266,18 +266,18 @@ class FullNodeStore:
def get_potential_blocks_received(self, height: uint32) -> asyncio.Event:
return self.potential_blocks_received[height]
async def add_potential_future_block(self, block: FullBlock):
def add_potential_future_block(self, block: FullBlock):
self.potential_future_blocks.append(block)
async def get_potential_future_blocks(self):
def get_potential_future_blocks(self):
return self.potential_future_blocks
async def add_candidate_block(
def add_candidate_block(
self, pos_hash: bytes32, body: Body, header: HeaderData, pos: ProofOfSpace,
):
self.candidate_blocks[pos_hash] = (body, header, pos, body.coinbase.height)
async def get_candidate_block(
def get_candidate_block(
self, pos_hash: bytes32
) -> Optional[Tuple[Body, HeaderData, ProofOfSpace]]:
res = self.candidate_blocks.get(pos_hash, None)
@ -285,19 +285,17 @@ class FullNodeStore:
return None
return (res[0], res[1], res[2])
async def clear_candidate_blocks_below(self, height: uint32) -> None:
def clear_candidate_blocks_below(self, height: uint32) -> None:
for key in list(self.candidate_blocks.keys()):
if self.candidate_blocks[key][3] < height:
del self.candidate_blocks[key]
async def add_unfinished_block(
def add_unfinished_block(
self, key: Tuple[bytes32, uint64], block: FullBlock
) -> None:
self.unfinished_blocks[key] = block
async def get_unfinished_block(
self, key: Tuple[bytes32, uint64]
) -> Optional[FullBlock]:
def get_unfinished_block(self, key: Tuple[bytes32, uint64]) -> Optional[FullBlock]:
return self.unfinished_blocks.get(key, None)
def seen_unfinished_block(self, header_hash: bytes32) -> bool:
@ -309,10 +307,10 @@ class FullNodeStore:
def clear_seen_unfinished_blocks(self) -> None:
self.seen_unfinished_blocks.clear()
async def get_unfinished_blocks(self) -> Dict[Tuple[bytes32, uint64], FullBlock]:
def get_unfinished_blocks(self) -> Dict[Tuple[bytes32, uint64], FullBlock]:
return self.unfinished_blocks.copy()
async def clear_unfinished_blocks_below(self, height: uint32) -> None:
def clear_unfinished_blocks_below(self, height: uint32) -> None:
for key in list(self.unfinished_blocks.keys()):
if self.unfinished_blocks[key].height < height:
del self.unfinished_blocks[key]
@ -323,8 +321,8 @@ class FullNodeStore:
def get_unfinished_block_leader(self) -> Tuple[bytes32, uint64]:
return self.unfinished_blocks_leader
async def set_proof_of_time_estimate_ips(self, estimate: uint64):
def set_proof_of_time_estimate_ips(self, estimate: uint64):
self.proof_of_time_estimate_ips = estimate
async def get_proof_of_time_estimate_ips(self) -> uint64:
def get_proof_of_time_estimate_ips(self) -> uint64:
return self.proof_of_time_estimate_ips

View File

@ -76,15 +76,15 @@ class TestStore:
# Save/get sync
for sync_mode in (False, True):
await db.set_sync_mode(sync_mode)
assert sync_mode == await db.get_sync_mode()
db.set_sync_mode(sync_mode)
assert sync_mode == db.get_sync_mode()
# clear sync info
await db.clear_sync_info()
# add/get potential tip, get potential tips num
await db.add_potential_tip(blocks[6])
assert blocks[6] == await db.get_potential_tip(blocks[6].header_hash)
db.add_potential_tip(blocks[6])
assert blocks[6] == db.get_potential_tip(blocks[6].header_hash)
# add/get potential trunk
header = genesis.header_block
@ -96,16 +96,16 @@ class TestStore:
assert genesis == await db.get_potential_block(uint32(0))
# Add/get candidate block
assert await db.get_candidate_block(0) is None
assert db.get_candidate_block(0) is None
partial = (
blocks[5].body,
blocks[5].header_block.header.data,
blocks[5].header_block.proof_of_space,
)
await db.add_candidate_block(blocks[5].header_hash, *partial)
assert await db.get_candidate_block(blocks[5].header_hash) == partial
await db.clear_candidate_blocks_below(uint32(8))
assert await db.get_candidate_block(blocks[5].header_hash) is None
db.add_candidate_block(blocks[5].header_hash, *partial)
assert db.get_candidate_block(blocks[5].header_hash) == partial
db.clear_candidate_blocks_below(uint32(8))
assert db.get_candidate_block(blocks[5].header_hash) is None
# Add/get unfinished block
i = 1
@ -113,29 +113,29 @@ class TestStore:
key = (block.header_hash, uint64(1000))
# Different database should have different data
await db_2.add_unfinished_block(key, block)
db_2.add_unfinished_block(key, block)
assert await db.get_unfinished_block(key) is None
await db.add_unfinished_block(key, block)
assert await db.get_unfinished_block(key) == block
assert len(await db.get_unfinished_blocks()) == i
assert db.get_unfinished_block(key) is None
db.add_unfinished_block(key, block)
assert db.get_unfinished_block(key) == block
assert len(db.get_unfinished_blocks()) == i
i += 1
await db.clear_unfinished_blocks_below(uint32(5))
assert len(await db.get_unfinished_blocks()) == 5
db.clear_unfinished_blocks_below(uint32(5))
assert len(db.get_unfinished_blocks()) == 5
# Set/get unf block leader
assert db.get_unfinished_block_leader() == (0, (1 << 64) - 1)
db.set_unfinished_block_leader(key)
assert db.get_unfinished_block_leader() == key
assert await db.get_disconnected_block(blocks[0].prev_header_hash) is None
assert db.get_disconnected_block(blocks[0].prev_header_hash) is None
# Disconnected blocks
for block in blocks:
await db.add_disconnected_block(block)
await db.get_disconnected_block(block.prev_header_hash) == block
db.add_disconnected_block(block)
db.get_disconnected_block(block.prev_header_hash) == block
await db.clear_disconnected_blocks_below(uint32(5))
assert await db.get_disconnected_block(blocks[4].prev_header_hash) is None
db.clear_disconnected_blocks_below(uint32(5))
assert db.get_disconnected_block(blocks[4].prev_header_hash) is None
h_hash_1 = bytes32(token_bytes(32))
assert not db.seen_unfinished_block(h_hash_1)
@ -172,10 +172,18 @@ class TestStore:
if random.random() < 0.5:
tasks.append(asyncio.create_task(db.add_block(blocks[rand_i])))
if random.random() < 0.5:
tasks.append(asyncio.create_task(db.add_potential_block(blocks[rand_i])))
tasks.append(
asyncio.create_task(db.add_potential_block(blocks[rand_i]))
)
if random.random() < 0.5:
tasks.append(asyncio.create_task(db.get_block(blocks[rand_i].header_hash)))
tasks.append(
asyncio.create_task(db.get_block(blocks[rand_i].header_hash))
)
if random.random() < 0.5:
tasks.append(asyncio.create_task(db.get_potential_block(blocks[rand_i].header_hash)))
tasks.append(
asyncio.create_task(
db.get_potential_block(blocks[rand_i].header_hash)
)
)
await asyncio.gather(*tasks)
await db.close()