From 30aa656a84b6801e151049ff9f0dfa3221eae2e2 Mon Sep 17 00:00:00 2001
From: Mariano Sorgente <3069354+mariano54@users.noreply.github.com>
Date: Wed, 6 Jan 2021 13:13:39 +0900
Subject: [PATCH] Ms.bug fixes (#615)
* on_disconnect callback called if present, for services (full_node, farmer, etc) when a connection is closed
* connections added or removed are reflected in UI
* No migration of wallet full node peer
* More blockchain_transaction tests re-enabled
* Blockchain tests uncommented
* get_block_peak fixed in blockchain.py
* Reduce some logging in tests, and asynciosqlite logs suppressed for the DEBUG level
---
.../src/components/fullNode/FullNode.jsx | 14 +-
requirements-dev.txt | 2 +-
src/cmds/configure.py | 5 +-
src/cmds/init.py | 1 +
src/consensus/block_body_validation.py | 5 +
src/consensus/block_header_validation.py | 83 +-
src/consensus/blockchain.py | 4 +-
src/farmer/farmer.py | 7 +-
src/farmer/farmer_api.py | 27 +-
src/full_node/full_node.py | 5 +-
src/full_node/full_node_store.py | 5 +
src/harvester/harvester.py | 6 +
src/introducer/introducer.py | 3 +-
src/rpc/full_node_rpc_api.py | 5 +-
src/rpc/rpc_server.py | 1 +
src/rpc/wallet_rpc_client.py | 13 +-
src/server/server.py | 11 +-
src/server/start_service.py | 1 +
src/timelord/timelord.py | 7 +-
src/types/peer_info.py | 7 +-
src/util/block_tools.py | 14 +-
src/util/logging.py | 1 +
src/wallet/cc_wallet/cc_utils.py | 6 +-
src/wallet/puzzles/test_cc.py | 8 +-
src/wallet/trade_manager.py | 4 +-
src/wallet/wallet_blockchain.py | 4 +-
src/wallet/wallet_transaction_store.py | 3 +-
tests/consensus/test_blockchain.py | 2966 ++++++++---------
tests/consensus/test_pot_iterations.py | 10 +-
.../full_node/test_blockchain_transactions.py | 857 +++--
tests/full_node/test_full_node.py | 4 +-
tests/full_node/test_mempool.py | 4 +-
tests/rpc/test_farmer_harvester_rpc.py | 3 -
tests/test_simulation.py | 3 +-
tests/time_out_assert.py | 5 +-
35 files changed, 2034 insertions(+), 2070 deletions(-)
diff --git a/electron-react/src/components/fullNode/FullNode.jsx b/electron-react/src/components/fullNode/FullNode.jsx
index 95222baf57..2cfd620590 100644
--- a/electron-react/src/components/fullNode/FullNode.jsx
+++ b/electron-react/src/components/fullNode/FullNode.jsx
@@ -155,7 +155,7 @@ const getStatusItems = (state, connected) => {
const status_items = [];
if (state.sync && state.sync.sync_mode) {
const progress = state.sync.sync_progress_sub_height;
- const tip = state.sync.sync_tip_height;
+ const tip = state.sync.sync_tip_sub_height;
const item = {
label: Status,
value: (
@@ -202,7 +202,7 @@ const getStatusItems = (state, connected) => {
};
status_items.push(item);
}
-
+
if (connected) {
status_items.push({
label: Connection Status,
@@ -241,7 +241,7 @@ const getStatusItems = (state, connected) => {
const peakTimestamp = state.peak?.foliage_block?.timestamp;
status_items.push({
label: Peak Time,
- value: peakTimestamp
+ value: peakTimestamp
? unix_to_short_date(Number.parseInt(peakTimestamp))
: '',
tooltip: (
@@ -400,16 +400,16 @@ const BlocksCard = () => {
-
+
{latestBlocks.map((record) => {
const isFinished = true; //record.finished_reward_slot_hashes && !!record.finished_reward_slot_hashes.length;
- const {
+ const {
foliage_block: {
height,
timestamp,
header_hash = 'mocked-hash',
prev_block_hash,
- }
+ }
} = record;
return (
@@ -456,7 +456,7 @@ const BlocksCard = () => {
)}
-
+
);
};
diff --git a/requirements-dev.txt b/requirements-dev.txt
index d43ead6d46..2aab7f4386 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1,4 +1,4 @@
-black>=19.10b0
+black>=20.8b1
# black Dependencies
appdirs~=1.4.4
attrs>=18.1.0
diff --git a/src/cmds/configure.py b/src/cmds/configure.py
index 14cd616196..f1f52c1686 100644
--- a/src/cmds/configure.py
+++ b/src/cmds/configure.py
@@ -1,4 +1,7 @@
-from src.util.config import load_config, save_config
+from src.util.config import (
+ load_config,
+ save_config,
+)
from argparse import ArgumentParser
from typing import Dict
from src.util.default_root import DEFAULT_ROOT_PATH
diff --git a/src/cmds/init.py b/src/cmds/init.py
index 6632813087..a1f9a62431 100644
--- a/src/cmds/init.py
+++ b/src/cmds/init.py
@@ -237,6 +237,7 @@ def chia_init(root_path: Path):
DO_NOT_MIGRATE_SETTINGS: List[str] = [
"full_node.introducer_peer",
"wallet.introducer_peer",
+ "wallet.full_node_peer",
"full_node.database_path",
"wallet.database_path",
"full_node.simulator_database_path",
diff --git a/src/consensus/block_body_validation.py b/src/consensus/block_body_validation.py
index 68d6497f4d..e727fa801e 100644
--- a/src/consensus/block_body_validation.py
+++ b/src/consensus/block_body_validation.py
@@ -31,6 +31,10 @@ from src.util.errors import Err
from src.util.hash import std_hash
from src.util.ints import uint64, uint32
+import logging
+
+log = logging.getLogger(__name__)
+
async def validate_block_body(
constants: ConsensusConstants,
@@ -232,6 +236,7 @@ async def validate_block_body(
additions_since_fork[c.name()] = (c, curr.sub_block_height)
for coinbase_coin in curr.get_included_reward_coins():
+ additions_since_fork[coinbase_coin.name()] = (coinbase_coin, curr.sub_block_height)
coinbases_since_fork[coinbase_coin.name()] = curr.sub_block_height
if curr.sub_block_height == 0:
break
diff --git a/src/consensus/block_header_validation.py b/src/consensus/block_header_validation.py
index c03fef7894..7ee5228e8e 100644
--- a/src/consensus/block_header_validation.py
+++ b/src/consensus/block_header_validation.py
@@ -253,9 +253,12 @@ async def validate_unfinished_header_block(
# 2o. Check challenge sub-slot hash in reward sub-slot
if sub_slot.challenge_chain.get_hash() != sub_slot.reward_chain.challenge_chain_sub_slot_hash:
- return None, ValidationError(
- Err.INVALID_CHALLENGE_SLOT_HASH_RC,
- "sub-slot hash in reward sub-slot mismatch",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_CHALLENGE_SLOT_HASH_RC,
+ "sub-slot hash in reward sub-slot mismatch",
+ ),
)
eos_vdf_iters: uint64 = sub_slot_iters
@@ -330,9 +333,12 @@ async def validate_unfinished_header_block(
if genesis_block:
# 2r. Check deficit (MIN_SUB.. deficit edge case for genesis block)
if sub_slot.reward_chain.deficit != constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK:
- return None, ValidationError(
- Err.INVALID_DEFICIT,
- f"genesis, expected deficit {constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK}",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_DEFICIT,
+ f"genesis, expected deficit {constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK}",
+ ),
)
else:
assert prev_sb is not None
@@ -342,10 +348,13 @@ async def validate_unfinished_header_block(
log.error(
constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK,
)
- return None, ValidationError(
- Err.INVALID_DEFICIT,
- f"expected deficit {constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK}, saw "
- f"{sub_slot.reward_chain.deficit}",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_DEFICIT,
+ f"expected deficit {constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK}, saw "
+ f"{sub_slot.reward_chain.deficit}",
+ ),
)
else:
# 2t. Otherwise, deficit stays the same at the slot ends, cannot reset until 0
@@ -358,17 +367,23 @@ async def validate_unfinished_header_block(
if ses_hash is not None:
# 3a. Check that genesis block does not have sub-epoch summary
if genesis_block:
- return None, ValidationError(
- Err.INVALID_SUB_EPOCH_SUMMARY_HASH,
- "genesis with sub-epoch-summary hash",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_SUB_EPOCH_SUMMARY_HASH,
+ "genesis with sub-epoch-summary hash",
+ ),
)
assert prev_sb is not None
# 3b. Check that we finished a slot and we finished a sub-epoch
if not new_sub_slot or not can_finish_se:
- return None, ValidationError(
- Err.INVALID_SUB_EPOCH_SUMMARY_HASH,
- f"new sub-slot: {new_sub_slot} finishes sub-epoch {can_finish_se}",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_SUB_EPOCH_SUMMARY_HASH,
+ f"new sub-slot: {new_sub_slot} finishes sub-epoch {can_finish_se}",
+ ),
)
# 3c. Check the actual sub-epoch is correct
@@ -383,16 +398,22 @@ async def validate_unfinished_header_block(
expected_hash = expected_sub_epoch_summary.get_hash()
if expected_hash != ses_hash:
log.error(f"{expected_sub_epoch_summary}")
- return None, ValidationError(
- Err.INVALID_SUB_EPOCH_SUMMARY,
- f"expected ses hash: {expected_hash} got {ses_hash} ",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_SUB_EPOCH_SUMMARY,
+ f"expected ses hash: {expected_hash} got {ses_hash} ",
+ ),
)
elif new_sub_slot and not genesis_block:
# 3d. Check that we don't have to include a sub-epoch summary
if can_finish_se or can_finish_epoch:
- return None, ValidationError(
- Err.INVALID_SUB_EPOCH_SUMMARY,
- "block finishes sub-epoch but ses-hash is None",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_SUB_EPOCH_SUMMARY,
+ "block finishes sub-epoch but ses-hash is None",
+ ),
)
# 4. Check if the number of sub-blocks is less than the max
@@ -511,9 +532,12 @@ async def validate_unfinished_header_block(
total_iters = uint128(prev_sb.total_iters - prev_sb.ip_iters(constants))
total_iters = uint128(total_iters + ip_iters)
if total_iters != header_block.reward_chain_sub_block.total_iters:
- return None, ValidationError(
- Err.INVALID_TOTAL_ITERS,
- f"expected {total_iters} got {header_block.reward_chain_sub_block.total_iters}",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_TOTAL_ITERS,
+ f"expected {total_iters} got {header_block.reward_chain_sub_block.total_iters}",
+ ),
)
sp_total_iters: uint128 = uint128(total_iters - ip_iters + sp_iters - (sub_slot_iters if overflow else 0))
@@ -919,9 +943,12 @@ async def validate_finished_header_block(
assert header_block.infused_challenge_chain_ip_proof is not None
# If we have an ICC chain, deficit must be 0, 1, 2 or 3
if deficit >= constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK - 1:
- return None, ValidationError(
- Err.INVALID_ICC_VDF,
- f"icc vdf and deficit is bigger or equal to {constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK - 1}",
+ return (
+ None,
+ ValidationError(
+ Err.INVALID_ICC_VDF,
+ f"icc vdf and deficit is bigger or equal to {constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK - 1}",
+ ),
)
if new_sub_slot:
last_ss = header_block.finished_sub_slots[-1]
diff --git a/src/consensus/blockchain.py b/src/consensus/blockchain.py
index b51a942a39..910b7d7c7d 100644
--- a/src/consensus/blockchain.py
+++ b/src/consensus/blockchain.py
@@ -143,11 +143,11 @@ class Blockchain:
async def get_block_peak(self) -> Optional[FullBlock]:
""" Return peak block"""
- if self.peak_height is None or self.peak_height == 0:
+ if self.peak_height is None:
return None
start = int(self.peak_height)
peak = None
- while start > 0:
+ while start >= 0:
block = await self.block_store.get_full_block(self.sub_height_to_hash[uint32(start)])
if block is not None and block.is_block():
peak = block
diff --git a/src/farmer/farmer.py b/src/farmer/farmer.py
index c844b4ea2e..a33579a226 100644
--- a/src/farmer/farmer.py
+++ b/src/farmer/farmer.py
@@ -3,6 +3,7 @@ import logging
import time
from typing import Dict, List, Optional, Callable, Tuple, Any
+import src.server.ws_connection as ws # lgtm [py/import-and-import-from]
from blspy import G1Element
from src.server.ws_connection import WSChiaConnection
@@ -42,7 +43,7 @@ class Farmer:
self.proofs_of_space: Dict[bytes32, List[Tuple[str, ProofOfSpace]]] = {}
# Quality string to plot identifier and challenge_hash, for use with harvester.RequestSignatures
- self.quality_str_to_identifiers: Dict[bytes32, Tuple[str, bytes32, bytes32]] = {}
+ self.quality_str_to_identifiers: Dict[bytes32, Tuple[str, bytes32, bytes32, bytes32]] = {}
# number of responses to each signage point
self.number_of_responses: Dict[bytes32, int] = {}
@@ -112,6 +113,10 @@ class Farmer:
if self.state_changed_callback is not None:
self.state_changed_callback(change, sp_hash)
+ def on_disconnect(self, connection: ws.WSChiaConnection):
+ self.log.info(f"peer disconnected {connection.get_peer_info()}")
+ self.state_changed("close_connection", bytes32([0] * 32))
+
def get_public_keys(self):
return [child_sk.get_g1() for child_sk in self._private_keys]
diff --git a/src/farmer/farmer_api.py b/src/farmer/farmer_api.py
index 3bfc5ba5b5..1d39139394 100644
--- a/src/farmer/farmer_api.py
+++ b/src/farmer/farmer_api.py
@@ -2,6 +2,7 @@ import time
from typing import Callable
from blspy import AugSchemeMPL, G2Element
+import src.server.ws_connection as ws
from src.consensus.pot_iterations import (
calculate_iterations_quality,
@@ -12,7 +13,7 @@ from src.protocols import harvester_protocol, farmer_protocol
from src.server.outbound_message import Message, NodeType
from src.types.pool_target import PoolTarget
from src.types.proof_of_space import ProofOfSpace
-from src.util.api_decorators import api_request
+from src.util.api_decorators import api_request, peer_required
from src.util.ints import uint32, uint64
@@ -26,7 +27,10 @@ class FarmerAPI:
self.farmer.state_changed_callback = callback
@api_request
- async def new_proof_of_space(self, new_proof_of_space: harvester_protocol.NewProofOfSpace):
+ @peer_required
+ async def new_proof_of_space(
+ self, new_proof_of_space: harvester_protocol.NewProofOfSpace, peer: ws.WSChiaConnection
+ ):
"""
This is a response from the harvester, for a NewChallenge. Here we check if the proof
of space is sufficiently good, and if so, we ask for the whole proof.
@@ -100,11 +104,11 @@ class FarmerAPI:
new_proof_of_space.plot_identifier,
new_proof_of_space.challenge_hash,
new_proof_of_space.sp_hash,
+ peer.peer_node_id,
)
self.farmer.cache_add_time[computed_quality_string] = uint64(int(time.time()))
- msg = Message("request_signatures", request)
- await self.farmer.server.send_to_all([msg], NodeType.HARVESTER)
+ return Message("request_signatures", request)
@api_request
async def respond_signatures(self, response: harvester_protocol.RespondSignatures):
@@ -250,20 +254,15 @@ class FarmerAPI:
self.farmer.log.error(f"Do not have quality string {full_node_request.quality_string}")
return
- (
- plot_identifier,
- challenge_hash,
- sp_hash,
- ) = self.farmer.quality_str_to_identifiers[full_node_request.quality_string]
+ (plot_identifier, challenge_hash, sp_hash, node_id) = self.farmer.quality_str_to_identifiers[
+ full_node_request.quality_string
+ ]
request = harvester_protocol.RequestSignatures(
plot_identifier,
challenge_hash,
sp_hash,
- [
- full_node_request.foliage_sub_block_hash,
- full_node_request.foliage_block_hash,
- ],
+ [full_node_request.foliage_sub_block_hash, full_node_request.foliage_block_hash],
)
msg = Message("request_signatures", request)
- await self.farmer.server.send_to_all([msg], NodeType.HARVESTER)
+ await self.farmer.server.send_to_specific([msg], node_id)
diff --git a/src/full_node/full_node.py b/src/full_node/full_node.py
index a8339dca40..dafa4de02c 100644
--- a/src/full_node/full_node.py
+++ b/src/full_node/full_node.py
@@ -85,6 +85,7 @@ class FullNode:
self.constants = consensus_constants
self.pow_pending: Set[bytes32] = set()
self.pow_creation: Dict[uint32, asyncio.Event] = {}
+ self.state_changed_callback: Optional[Callable] = None
if name:
self.log = logging.getLogger(name)
@@ -284,6 +285,7 @@ class FullNode:
and challenges to timelords.
"""
+ self._state_changed("add_connection")
if self.full_node_peers is not None:
asyncio.create_task(self.full_node_peers.on_connect(connection))
@@ -321,8 +323,9 @@ class FullNode:
elif connection.connection_type is NodeType.TIMELORD:
await self.send_peak_to_timelords()
- async def _on_disconnect(self, connection: ws.WSChiaConnection):
+ def on_disconnect(self, connection: ws.WSChiaConnection):
self.log.info(f"peer disconnected {connection.get_peer_info()}")
+ self._state_changed("close_connection")
def _num_needed_peers(self) -> int:
assert self.server is not None
diff --git a/src/full_node/full_node_store.py b/src/full_node/full_node_store.py
index a78674ac21..3217e16e05 100644
--- a/src/full_node/full_node_store.py
+++ b/src/full_node/full_node_store.py
@@ -382,6 +382,11 @@ class FullNodeStore:
cc_vdf_info_expected,
):
return False
+
+ if rc_vdf_info_expected.challenge != signage_point.rc_vdf.challenge:
+ # This signage point is probably outdated
+ return False
+
if not signage_point.rc_proof.is_valid(
self.constants,
ClassgroupElement.get_default_element(),
diff --git a/src/harvester/harvester.py b/src/harvester/harvester.py
index d7ff6d347d..00f436f502 100644
--- a/src/harvester/harvester.py
+++ b/src/harvester/harvester.py
@@ -1,5 +1,6 @@
import logging
import asyncio
+import src.server.ws_connection as ws # lgtm [py/import-and-import-from]
from concurrent.futures.thread import ThreadPoolExecutor
from pathlib import Path
from typing import Dict, Optional, Tuple, List, Callable, Set
@@ -51,6 +52,7 @@ class Harvester:
self.constants = constants
self.cached_challenges = []
self.log = log
+ self.state_changed_callback: Optional[Callable] = None
async def _start(self):
self._refresh_lock = asyncio.Lock()
@@ -69,6 +71,10 @@ class Harvester:
if self.state_changed_callback is not None:
self.state_changed_callback(change)
+ def on_disconnect(self, connection: ws.WSChiaConnection):
+ self.log.info(f"peer disconnected {connection.get_peer_info()}")
+ self._state_changed("close_connection")
+
def get_plots(self) -> Tuple[List[Dict], List[str], List[str]]:
response_plots: List[Dict] = []
for path, plot_info in self.provers.items():
diff --git a/src/introducer/introducer.py b/src/introducer/introducer.py
index 1cfe245295..d46b9847ae 100644
--- a/src/introducer/introducer.py
+++ b/src/introducer/introducer.py
@@ -1,7 +1,7 @@
import asyncio
import logging
import time
-from typing import Dict, Optional
+from typing import Dict, Optional, Callable
from src.types.sized_bytes import bytes32
from src.server.server import ChiaServer
@@ -15,6 +15,7 @@ class Introducer:
self._shut_down = False
self.server: Optional[ChiaServer] = None
self.log = logging.getLogger(__name__)
+ self.state_changed_callback: Optional[Callable] = None
async def _start(self):
self._vetting_task = asyncio.create_task(self._vetting_loop())
diff --git a/src/rpc/full_node_rpc_api.py b/src/rpc/full_node_rpc_api.py
index d95300d52b..55dc0a3029 100644
--- a/src/rpc/full_node_rpc_api.py
+++ b/src/rpc/full_node_rpc_api.py
@@ -97,10 +97,7 @@ class FullNodeRpcApi:
uint32(max(1, full_peak.sub_block_height - 1000))
].hex()
space = await self.get_network_space(
- {
- "newer_block_header_hash": newer_block_hex,
- "older_block_header_hash": older_block_hex,
- }
+ {"newer_block_header_hash": newer_block_hex, "older_block_header_hash": older_block_hex}
)
else:
space = {"space": uint128(0)}
diff --git a/src/rpc/rpc_server.py b/src/rpc/rpc_server.py
index f67e4ab573..68f76e8d91 100644
--- a/src/rpc/rpc_server.py
+++ b/src/rpc/rpc_server.py
@@ -45,6 +45,7 @@ class RpcServer:
if self.websocket is None:
return
payloads: List[Dict] = await self.rpc_api._state_changed(*args)
+ log.error(f"State changed: {change}")
if change == "add_connection" or change == "close_connection":
data = await self.get_connections({})
diff --git a/src/rpc/wallet_rpc_client.py b/src/rpc/wallet_rpc_client.py
index c821b609c1..04850aaf70 100644
--- a/src/rpc/wallet_rpc_client.py
+++ b/src/rpc/wallet_rpc_client.py
@@ -21,12 +21,9 @@ class WalletRpcClient(RpcClient):
try:
return await self.fetch(
"log_in",
- {
- "host": "https://backup.chia.net",
- "fingerprint": fingerprint,
- "type": "start",
- },
+ {"host": "https://backup.chia.net", "fingerprint": fingerprint, "type": "start"},
)
+
except ValueError as e:
return e.args[0]
@@ -48,11 +45,7 @@ class WalletRpcClient(RpcClient):
try:
return await self.fetch(
"log_in",
- {
- "host": "https://backup.chia.net",
- "fingerprint": fingerprint,
- "type": "skip",
- },
+ {"host": "https://backup.chia.net", "fingerprint": fingerprint, "type": "skip"},
)
except ValueError as e:
return e.args[0]
diff --git a/src/server/server.py b/src/server/server.py
index 4fd087d8d9..bc91e4769a 100644
--- a/src/server/server.py
+++ b/src/server/server.py
@@ -11,9 +11,7 @@ from aiohttp import web, ClientTimeout, client_exceptions, ClientSession
from src.server.introducer_peers import IntroducerPeers
from src.server.outbound_message import NodeType, Message, Payload
-from src.server.ssl_context import (
- load_ssl_paths,
-)
+from src.server.ssl_context import load_ssl_paths
from src.server.ws_connection import WSChiaConnection
from src.types.peer_info import PeerInfo
from src.types.sized_bytes import bytes32
@@ -49,6 +47,7 @@ class ChiaServer:
def __init__(
self,
port: int,
+ node: Any,
api: Any,
local_type: NodeType,
ping_interval: int,
@@ -78,7 +77,7 @@ class ChiaServer:
# Open connection tasks. These will be cancelled if
self._oc_tasks: List[asyncio.Task] = []
- # Taks list to keep references to tasks, so they don'y get GCd
+ # Taks list to keep references to tasks, so they don't get GCd
self._tasks: List[asyncio.Task] = []
if name:
@@ -89,6 +88,7 @@ class ChiaServer:
# Our unique random node id that we will send to other peers, regenerated on launch
self.node_id = create_node_id()
self.api = api
+ self.node = node
self.root_path = root_path
self.config = config
self.on_connect: Optional[Callable] = None
@@ -293,6 +293,9 @@ class ChiaServer:
self.connection_by_type[connection.connection_type].pop(connection.peer_node_id)
else:
self.log.error(f"Invalid connection type for connection {connection}, while closing")
+ on_disconnect = getattr(self.node, "on_disconnect", None)
+ if on_disconnect is not None:
+ on_disconnect(connection)
async def incoming_api_task(self):
self.tasks = set()
diff --git a/src/server/start_service.py b/src/server/start_service.py
index 6eb05c625c..8ccebfdb06 100644
--- a/src/server/start_service.py
+++ b/src/server/start_service.py
@@ -67,6 +67,7 @@ class Service:
self._server = ChiaServer(
advertised_port,
+ node,
peer_api,
node_type,
ping_interval,
diff --git a/src/timelord/timelord.py b/src/timelord/timelord.py
index b6310bbe5a..299a2ee644 100644
--- a/src/timelord/timelord.py
+++ b/src/timelord/timelord.py
@@ -4,7 +4,7 @@ import io
import logging
import time
import traceback
-from typing import Dict, List, Optional, Tuple
+from typing import Dict, List, Optional, Tuple, Callable
from chiavdf import create_discriminant
@@ -21,9 +21,7 @@ from src.timelord.timelord_state import LastState
from src.timelord.types import Chain, IterationType, StateType
from src.types.classgroup import ClassgroupElement
from src.types.end_of_slot_bundle import EndOfSubSlotBundle
-from src.types.reward_chain_sub_block import (
- RewardChainSubBlock,
-)
+from src.types.reward_chain_sub_block import RewardChainSubBlock
from src.types.sized_bytes import bytes32
from src.types.slots import (
ChallengeChainSubSlot,
@@ -85,6 +83,7 @@ class Timelord:
self.vdf_failures_count: int = 0
self.total_unfinished: int = 0
self.total_infused: int = 0
+ self.state_changed_callback: Optional[Callable] = None
async def _start(self):
self.lock: asyncio.Lock = asyncio.Lock()
diff --git a/src/types/peer_info.py b/src/types/peer_info.py
index 58f3b508b8..b6989bf84a 100644
--- a/src/types/peer_info.py
+++ b/src/types/peer_info.py
@@ -37,12 +37,7 @@ class PeerInfo(Streamable):
ip_v4 = ipaddress.IPv4Address(self.host)
ip = ipaddress.IPv6Address(int(ipaddress.IPv6Address("2002::")) | (int(ip_v4) << 80))
key = ip.packed
- key += bytes(
- [
- self.port // 0x100,
- self.port & 0x0FF,
- ]
- )
+ key += bytes([self.port // 0x100, self.port & 0x0FF])
return key
def get_group(self):
diff --git a/src/util/block_tools.py b/src/util/block_tools.py
index 47d352c72b..5284988b1b 100644
--- a/src/util/block_tools.py
+++ b/src/util/block_tools.py
@@ -16,9 +16,7 @@ from src.consensus.deficit import calculate_deficit
from src.cmds.init import create_default_chia_config, initialize_ssl
from src.cmds.plots import create_plots
-from src.consensus.coinbase import (
- create_puzzlehash_for_pk,
-)
+from src.consensus.coinbase import create_puzzlehash_for_pk
from src.consensus.constants import ConsensusConstants
from src.consensus.pot_iterations import (
calculate_ip_iters,
@@ -246,7 +244,7 @@ class BlockTools:
timestamp=uint64(int(time.time())),
farmer_reward_puzzle_hash=farmer_reward_puzzle_hash,
)
- print(f"Created block 0 iters: {genesis.total_iters}")
+ log.info(f"Created block 0 iters: {genesis.total_iters}")
num_empty_slots_added = skip_slots
block_list = [genesis]
num_blocks -= 1
@@ -384,7 +382,7 @@ class BlockTools:
sub_blocks_added_this_sub_slot += 1
sub_blocks[full_block.header_hash] = sub_block_record
- print(
+ log.info(
f"Created block {sub_block_record.sub_block_height} ove=False, iters "
f"{sub_block_record.total_iters}"
)
@@ -456,7 +454,7 @@ class BlockTools:
new_sub_slot_iters: Optional[uint64] = sub_epoch_summary.new_sub_slot_iters
new_difficulty: Optional[uint64] = sub_epoch_summary.new_difficulty
- print("Sub epoch summary:", sub_epoch_summary)
+ log.info(f"Sub epoch summary: {sub_epoch_summary}")
else:
ses_hash = None
new_sub_slot_iters = None
@@ -518,7 +516,7 @@ class BlockTools:
if transaction_data_included:
transaction_data = None
sub_slots_finished += 1
- print(
+ log.info(
f"Sub slot finished. Sub-blocks included: {sub_blocks_added_this_sub_slot} sub_blocks_per_slot: "
f"{(len(block_list) - initial_block_list_len)/sub_slots_finished}"
)
@@ -597,7 +595,7 @@ class BlockTools:
block_list.append(full_block)
sub_blocks_added_this_sub_slot += 1
- print(
+ log.info(
f"Created block {sub_block_record.sub_block_height } ov=True, iters "
f"{sub_block_record.total_iters}"
)
diff --git a/src/util/logging.py b/src/util/logging.py
index 2fb2cd545e..6ddc081d4b 100644
--- a/src/util/logging.py
+++ b/src/util/logging.py
@@ -47,6 +47,7 @@ def initialize_logging(service_name: str, logging_config: Dict, root_path: Path)
logger.setLevel(logging.INFO)
elif logging_config["log_level"] == "DEBUG":
logger.setLevel(logging.DEBUG)
+ logging.getLogger("aiosqlite").setLevel(logging.INFO) # Too much logging on debug level
else:
logger.setLevel(logging.INFO)
else:
diff --git a/src/wallet/cc_wallet/cc_utils.py b/src/wallet/cc_wallet/cc_utils.py
index 748748614d..28d782404d 100644
--- a/src/wallet/cc_wallet/cc_utils.py
+++ b/src/wallet/cc_wallet/cc_utils.py
@@ -59,11 +59,7 @@ def lineage_proof_for_cc_parent(parent_coin: Coin, parent_inner_puzzle_hash: byt
return Program.to(
(
1,
- [
- parent_coin.parent_coin_info,
- parent_inner_puzzle_hash,
- parent_coin.amount,
- ],
+ [parent_coin.parent_coin_info, parent_inner_puzzle_hash, parent_coin.amount],
)
)
diff --git a/src/wallet/puzzles/test_cc.py b/src/wallet/puzzles/test_cc.py
index 32e1006d5b..f6ffbe3412 100644
--- a/src/wallet/puzzles/test_cc.py
+++ b/src/wallet/puzzles/test_cc.py
@@ -19,12 +19,8 @@ from src.wallet.cc_wallet.cc_utils import (
spend_bundle_for_spendable_ccs,
CC_MOD,
)
-from src.wallet.puzzles.genesis_by_coin_id_with_0 import (
- create_genesis_or_zero_coin_checker,
-)
-from src.wallet.puzzles.genesis_by_puzzle_hash_with_0 import (
- create_genesis_puzzle_or_zero_coin_checker,
-)
+from src.wallet.puzzles.genesis_by_coin_id_with_0 import create_genesis_or_zero_coin_checker
+from src.wallet.puzzles.genesis_by_puzzle_hash_with_0 import create_genesis_puzzle_or_zero_coin_checker
CONDITIONS = dict((k, bytes(v)[0]) for k, v in ConditionOpcode.__members__.items())
diff --git a/src/wallet/trade_manager.py b/src/wallet/trade_manager.py
index e20bca2859..a395edb9c8 100644
--- a/src/wallet/trade_manager.py
+++ b/src/wallet/trade_manager.py
@@ -16,9 +16,7 @@ from src.util.hash import std_hash
from src.util.ints import uint32, uint64
from src.wallet.cc_wallet import cc_utils
from src.wallet.cc_wallet.cc_wallet import CCWallet
-from src.wallet.puzzles.genesis_by_coin_id_with_0 import (
- genesis_coin_id_for_genesis_coin_checker,
-)
+from src.wallet.puzzles.genesis_by_coin_id_with_0 import genesis_coin_id_for_genesis_coin_checker
from src.wallet.trade_record import TradeRecord
from src.wallet.trading.trade_status import TradeStatus
from src.wallet.trading.trade_store import TradeStore
diff --git a/src/wallet/wallet_blockchain.py b/src/wallet/wallet_blockchain.py
index 58edf1512c..69fa19ea14 100644
--- a/src/wallet/wallet_blockchain.py
+++ b/src/wallet/wallet_blockchain.py
@@ -20,9 +20,7 @@ from src.types.unfinished_block import UnfinishedBlock
from src.util.errors import Err
from src.util.ints import uint32, uint64
from src.consensus.find_fork_point import find_fork_point_in_chain
-from src.consensus.block_header_validation import (
- validate_finished_header_block,
-)
+from src.consensus.block_header_validation import validate_finished_header_block
from src.wallet.block_record import HeaderBlockRecord
from src.wallet.wallet_coin_store import WalletCoinStore
from src.wallet.wallet_block_store import WalletBlockStore
diff --git a/src/wallet/wallet_transaction_store.py b/src/wallet/wallet_transaction_store.py
index c13c730661..8eb5eb9204 100644
--- a/src/wallet/wallet_transaction_store.py
+++ b/src/wallet/wallet_transaction_store.py
@@ -71,7 +71,8 @@ class WalletTransactionStore:
return self
async def _init_cache(self):
- print("init cache here")
+ # init cache here
+ pass
async def _clear_database(self):
cursor = await self.db_connection.execute("DELETE FROM transaction_record")
diff --git a/tests/consensus/test_blockchain.py b/tests/consensus/test_blockchain.py
index d2e8a11394..9c2b6528af 100644
--- a/tests/consensus/test_blockchain.py
+++ b/tests/consensus/test_blockchain.py
@@ -1,9 +1,9 @@
# flake8: noqa: F811, F401
import asyncio
from dataclasses import replace
+import logging
import pytest
from blspy import AugSchemeMPL, G2Element
-from pytest import raises
from src.consensus.blockchain import ReceiveBlockResult
from src.types.classgroup import ClassgroupElement
@@ -23,6 +23,8 @@ from tests.full_node.fixtures import default_1000_blocks # noqa: F401
from tests.full_node.fixtures import default_400_blocks # noqa: F401
from tests.full_node.fixtures import default_10000_blocks # noqa: F401
+log = logging.getLogger(__name__)
+
@pytest.fixture(scope="module")
def event_loop():
@@ -55,1489 +57,1481 @@ class TestGenesisBlock:
if proof.is_valid(test_constants, ClassgroupElement.get_default_element(), vdf) is False:
raise Exception("invalid proof")
+ @pytest.mark.asyncio
+ async def test_non_overflow_genesis(self, empty_blockchain):
+ assert empty_blockchain.get_peak() is None
+ genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
+ result, err, _ = await empty_blockchain.receive_block(genesis, False)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert empty_blockchain.get_peak().sub_block_height == 0
-#
-#
-#
-# @pytest.mark.asyncio
-# async def test_non_overflow_genesis(self, empty_blockchain):
-# assert empty_blockchain.get_peak() is None
-# genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
-# result, err, _ = await empty_blockchain.receive_block(genesis, False)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert empty_blockchain.get_peak().sub_block_height == 0
-#
-# @pytest.mark.asyncio
-# async def test_overflow_genesis(self, empty_blockchain):
-# genesis = bt.get_consecutive_blocks(1, force_overflow=True)[0]
-# result, err, _ = await empty_blockchain.receive_block(genesis, False)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_genesis_empty_slots(self, empty_blockchain):
-# genesis = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=3)[0]
-# result, err, _ = await empty_blockchain.receive_block(genesis, False)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_overflow_genesis_empty_slots(self, empty_blockchain):
-# genesis = bt.get_consecutive_blocks(1, force_overflow=True, skip_slots=3)[0]
-# result, err, _ = await empty_blockchain.receive_block(genesis, False)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_genesis_validate_1(self, empty_blockchain):
-# genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
-# bad_prev = bytes([1] * 32)
-# genesis = recursive_replace(genesis, "foliage_sub_block.prev_sub_block_hash", bad_prev)
-# result, err, _ = await empty_blockchain.receive_block(genesis, False)
-# assert err == Err.INVALID_PREV_BLOCK_HASH
-#
-#
-# class TestBlockHeaderValidation:
-# @pytest.mark.asyncio
-# async def test_long_chain(self, empty_blockchain, default_1000_blocks):
-# blocks = default_1000_blocks
-# for block in blocks:
-# if (
-# len(block.finished_sub_slots) > 0
-# and block.finished_sub_slots[0].challenge_chain.subepoch_summary_hash is not None
-# ):
-# # Sub/Epoch. Try using a bad ssi and difficulty to test 2m and 2n
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[0],
-# "challenge_chain.new_sub_slot_iters",
-# uint64(10000000),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_NEW_SUB_SLOT_ITERS
-# new_finished_ss_2 = recursive_replace(
-# block.finished_sub_slots[0],
-# "challenge_chain.new_difficulty",
-# uint64(10000000),
-# )
-# block_bad_2 = recursive_replace(
-# block, "finished_sub_slots", [new_finished_ss_2] + block.finished_sub_slots[1:]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_2)
-# assert err == Err.INVALID_NEW_DIFFICULTY
-#
-# # 3c
-# new_finished_ss_3: EndOfSubSlotBundle = recursive_replace(
-# block.finished_sub_slots[0],
-# "challenge_chain.subepoch_summary_hash",
-# bytes([0] * 32),
-# )
-# new_finished_ss_3 = recursive_replace(
-# new_finished_ss_3,
-# "reward_chain.challenge_chain_sub_slot_hash",
-# new_finished_ss_3.challenge_chain.get_hash(),
-# )
-# block_bad_3 = recursive_replace(
-# block, "finished_sub_slots", [new_finished_ss_3] + block.finished_sub_slots[1:]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_3)
-# assert err == Err.INVALID_SUB_EPOCH_SUMMARY
-#
-# # 3d
-# new_finished_ss_4 = recursive_replace(
-# block.finished_sub_slots[0],
-# "challenge_chain.subepoch_summary_hash",
-# None,
-# )
-# new_finished_ss_4 = recursive_replace(
-# new_finished_ss_4,
-# "reward_chain.challenge_chain_sub_slot_hash",
-# new_finished_ss_4.challenge_chain.get_hash(),
-# )
-# block_bad_4 = recursive_replace(
-# block, "finished_sub_slots", [new_finished_ss_4] + block.finished_sub_slots[1:]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_4)
-# assert err == Err.INVALID_SUB_EPOCH_SUMMARY or err == Err.INVALID_NEW_SUB_SLOT_ITERS
-#
-# result, err, _ = await empty_blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-# print(
-# f"Added block {block.sub_block_height} total iters {block.total_iters} new slot? {len(block.finished_sub_slots)}"
-# )
-# assert empty_blockchain.get_peak().sub_block_height == len(blocks) - 1
-#
-# @pytest.mark.asyncio
-# async def test_unfinished_blocks(self, empty_blockchain):
-# blockchain = empty_blockchain
-# blocks = bt.get_consecutive_blocks(2)
-# for block in blocks[:-1]:
-# result, err, _ = await blockchain.receive_block(block)
-# assert result == ReceiveBlockResult.NEW_PEAK
-# block = blocks[-1]
-# unf = UnfinishedBlock(
-# block.finished_sub_slots,
-# block.reward_chain_sub_block.get_unfinished(),
-# block.challenge_chain_sp_proof,
-# block.reward_chain_sp_proof,
-# block.foliage_sub_block,
-# block.foliage_block,
-# block.transactions_info,
-# block.transactions_generator,
-# )
-# _, err = await blockchain.validate_unfinished_block(unf, False)
-# assert err is None
-# result, err, _ = await blockchain.receive_block(block)
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
-# block = blocks[-1]
-# unf = UnfinishedBlock(
-# block.finished_sub_slots,
-# block.reward_chain_sub_block.get_unfinished(),
-# block.challenge_chain_sp_proof,
-# block.reward_chain_sp_proof,
-# block.foliage_sub_block,
-# block.foliage_block,
-# block.transactions_info,
-# block.transactions_generator,
-# )
-# _, err = await blockchain.validate_unfinished_block(unf, False)
-# assert err is None
-#
-# @pytest.mark.asyncio
-# async def test_empty_genesis(self, empty_blockchain):
-# blockchain = empty_blockchain
-# for block in bt.get_consecutive_blocks(2, skip_slots=3):
-# result, err, _ = await blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_empty_slots_non_genesis(self, empty_blockchain):
-# blockchain = empty_blockchain
-# blocks = bt.get_consecutive_blocks(10)
-# for block in blocks:
-# result, err, _ = await blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# blocks = bt.get_consecutive_blocks(10, skip_slots=2, block_list_input=blocks)
-# for block in blocks[10:]:
-# result, err, _ = await blockchain.receive_block(block)
-# assert err is None
-# assert blockchain.get_peak().sub_block_height == 19
-#
-# @pytest.mark.asyncio
-# async def test_one_sb_per_slot(self, empty_blockchain):
-# blockchain = empty_blockchain
-# num_blocks = 20
-# blocks = []
-# for i in range(num_blocks):
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
-# result, err, _ = await blockchain.receive_block(blocks[-1])
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert blockchain.get_peak().sub_block_height == num_blocks - 1
-#
-# @pytest.mark.asyncio
-# async def test_one_sb_per_two_slots(self, empty_blockchain):
-# blockchain = empty_blockchain
-# num_blocks = 20
-# blocks = []
-# for i in range(num_blocks): # Same thing, but 2 sub-slots per sub-block
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2)
-# result, err, _ = await blockchain.receive_block(blocks[-1])
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert blockchain.get_peak().sub_block_height == num_blocks - 1
-#
-# @pytest.mark.asyncio
-# async def test_one_sb_per_five_slots(self, empty_blockchain):
-# blockchain = empty_blockchain
-# num_blocks = 10
-# blocks = []
-# for i in range(num_blocks): # Same thing, but 5 sub-slots per sub-block
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=5)
-# result, err, _ = await blockchain.receive_block(blocks[-1])
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert blockchain.get_peak().sub_block_height == num_blocks - 1
-#
-# @pytest.mark.asyncio
-# async def test_basic_chain_overflow(self, empty_blockchain):
-# blocks = bt.get_consecutive_blocks(5, force_overflow=True)
-# for block in blocks:
-# result, err, _ = await empty_blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-# print(f"added {block.sub_block_height} {block.total_iters}")
-# assert empty_blockchain.get_peak().sub_block_height == len(blocks) - 1
-#
-# @pytest.mark.asyncio
-# async def test_one_sb_per_two_slots_force_overflow(self, empty_blockchain):
-# blockchain = empty_blockchain
-# num_blocks = 10
-# blocks = []
-# for i in range(num_blocks):
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2, force_overflow=True)
-# result, err, _ = await blockchain.receive_block(blocks[-1])
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert blockchain.get_peak().sub_block_height == num_blocks - 1
-#
-# @pytest.mark.asyncio
-# async def test_invalid_prev(self, empty_blockchain):
-# # 1
-# blocks = bt.get_consecutive_blocks(2, force_overflow=False)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_1_bad = recursive_replace(blocks[-1], "foliage_sub_block.prev_sub_block_hash", bytes([0] * 32))
-# print(block_1_bad)
-#
-# result, err, _ = await empty_blockchain.receive_block(block_1_bad)
-# assert result == ReceiveBlockResult.DISCONNECTED_BLOCK
-#
-# @pytest.mark.asyncio
-# async def test_invalid_pospace(self, empty_blockchain):
-# # 2
-# blocks = bt.get_consecutive_blocks(2, force_overflow=False)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_1_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.proof_of_space.proof", bytes([0] * 32))
-#
-# result, err, _ = await empty_blockchain.receive_block(block_1_bad)
-# assert result == ReceiveBlockResult.INVALID_BLOCK
-# assert err == Err.INVALID_POSPACE
-#
-# @pytest.mark.asyncio
-# async def test_invalid_sub_slot_challenge_hash_genesis(self, empty_blockchain):
-# # 2a
-# blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
-# new_finished_ss = recursive_replace(
-# blocks[0].finished_sub_slots[0],
-# "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
-# bytes([2] * 32),
-# )
-# block_0_bad = recursive_replace(
-# blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
-# )
-#
-# result, err, _ = await empty_blockchain.receive_block(block_0_bad)
-# assert result == ReceiveBlockResult.INVALID_BLOCK
-# assert err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
-#
-# @pytest.mark.asyncio
-# async def test_invalid_sub_slot_challenge_hash_non_genesis(self, empty_blockchain):
-# # 2b
-# blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
-# blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1, block_list_input=blocks)
-# print(blocks)
-# new_finished_ss = recursive_replace(
-# blocks[1].finished_sub_slots[0],
-# "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
-# bytes([2] * 32),
-# )
-# block_1_bad = recursive_replace(
-# blocks[1], "finished_sub_slots", [new_finished_ss] + blocks[1].finished_sub_slots[1:]
-# )
-#
-# _, _, _ = await empty_blockchain.receive_block(blocks[0])
-# result, err, _ = await empty_blockchain.receive_block(block_1_bad)
-# assert result == ReceiveBlockResult.INVALID_BLOCK
-# assert err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
-#
-# @pytest.mark.asyncio
-# async def test_invalid_sub_slot_challenge_hash_empty_ss(self, empty_blockchain):
-# # 2c
-# blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
-# blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=2, block_list_input=blocks)
-# new_finished_ss = recursive_replace(
-# blocks[1].finished_sub_slots[-1],
-# "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
-# bytes([2] * 32),
-# )
-# block_1_bad = recursive_replace(
-# blocks[1], "finished_sub_slots", blocks[1].finished_sub_slots[:-1] + [new_finished_ss]
-# )
-#
-# _, _, _ = await empty_blockchain.receive_block(blocks[0])
-# result, err, _ = await empty_blockchain.receive_block(block_1_bad)
-# assert result == ReceiveBlockResult.INVALID_BLOCK
-# assert err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
-#
-# @pytest.mark.asyncio
-# async def test_genesis_no_icc(self, empty_blockchain):
-# # 2d
-# blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
-# new_finished_ss = recursive_replace(
-# blocks[0].finished_sub_slots[0],
-# "infused_challenge_chain",
-# InfusedChallengeChainSubSlot(
-# VDFInfo(
-# bytes([0] * 32),
-# uint64(1200),
-# ClassgroupElement.get_default_element(),
-# )
-# ),
-# )
-# block_0_bad = recursive_replace(
-# blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
-# )
-#
-# result, err, _ = await empty_blockchain.receive_block(block_0_bad)
-# assert result == ReceiveBlockResult.INVALID_BLOCK
-# assert err == Err.SHOULD_NOT_HAVE_ICC
-#
-# @pytest.mark.asyncio
-# async def test_invalid_icc_sub_slot_vdf(self, empty_blockchain):
-# blocks = bt.get_consecutive_blocks(10)
-# for block in blocks:
-# if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is not None:
-# # Bad iters
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[-1],
-# "infused_challenge_chain",
-# InfusedChallengeChainSubSlot(
-# replace(
-# block.finished_sub_slots[
-# -1
-# ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf,
-# number_of_iterations=10000000,
-# )
-# ),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_ICC_EOS_VDF
-#
-# # Bad output
-# new_finished_ss_2 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "infused_challenge_chain",
-# InfusedChallengeChainSubSlot(
-# replace(
-# block.finished_sub_slots[
-# -1
-# ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf,
-# output=ClassgroupElement.get_default_element(),
-# )
-# ),
-# )
-# block_bad_2 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_2)
-# assert err == Err.INVALID_ICC_EOS_VDF
-#
-# # Bad challenge hash
-# new_finished_ss_3 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "infused_challenge_chain",
-# InfusedChallengeChainSubSlot(
-# replace(
-# block.finished_sub_slots[
-# -1
-# ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf,
-# challenge=bytes([0] * 32),
-# )
-# ),
-# )
-# block_bad_3 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_3)
-# assert err == Err.INVALID_ICC_EOS_VDF
-#
-# # Bad proof
-# new_finished_ss_5 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "proofs.infused_challenge_chain_slot_proof",
-# VDFProof(uint8(0), b"1239819023890"),
-# )
-# block_bad_5 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_5)
-# assert err == Err.INVALID_ICC_EOS_VDF
-#
-# result, err, _ = await empty_blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_invalid_icc_into_cc(self, empty_blockchain):
-# blockchain = empty_blockchain
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# case_1, case_2 = False, False
-# while not case_1 or not case_2:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
-# block = blocks[-1]
-# if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is not None:
-# if (
-# block.finished_sub_slots[-1].reward_chain.deficit
-# == test_constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK
-# ):
-# # 2g
-# case_1 = True
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[-1],
-# "challenge_chain",
-# replace(
-# block.finished_sub_slots[-1].challenge_chain,
-# infused_challenge_chain_sub_slot_hash=bytes([1] * 32),
-# ),
-# )
-# else:
-# # 2h
-# case_2 = True
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[-1],
-# "challenge_chain",
-# replace(
-# block.finished_sub_slots[-1].challenge_chain,
-# infused_challenge_chain_sub_slot_hash=block.finished_sub_slots[
-# -1
-# ].infused_challenge_chain.get_hash(),
-# ),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
-# )
-# result, err, _ = await blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_ICC_HASH_CC
-#
-# # 2i
-# new_finished_ss_bad_rc = recursive_replace(
-# block.finished_sub_slots[-1],
-# "reward_chain",
-# replace(block.finished_sub_slots[-1].reward_chain, infused_challenge_chain_sub_slot_hash=None),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
-# )
-# result, err, _ = await blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_ICC_HASH_RC
-# elif len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is None:
-# # 2j
-# new_finished_ss_bad_cc = recursive_replace(
-# block.finished_sub_slots[-1],
-# "challenge_chain",
-# replace(
-# block.finished_sub_slots[-1].challenge_chain,
-# infused_challenge_chain_sub_slot_hash=bytes([1] * 32),
-# ),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_cc]
-# )
-# print(len(block.finished_sub_slots))
-# result, err, _ = await blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_ICC_HASH_CC
-#
-# # 2k
-# new_finished_ss_bad_rc = recursive_replace(
-# block.finished_sub_slots[-1],
-# "reward_chain",
-# replace(
-# block.finished_sub_slots[-1].reward_chain, infused_challenge_chain_sub_slot_hash=bytes([1] * 32)
-# ),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
-# )
-# result, err, _ = await blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_ICC_HASH_RC
-#
-# # Finally, add the block properly
-# result, err, _ = await blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_empty_slot_no_ses(self, empty_blockchain):
-# # 2l
-# blockchain = empty_blockchain
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=4)
-#
-# new_finished_ss = recursive_replace(
-# blocks[-1].finished_sub_slots[-1],
-# "challenge_chain",
-# replace(blocks[-1].finished_sub_slots[-1].challenge_chain, subepoch_summary_hash=std_hash(b"0")),
-# )
-# block_bad = recursive_replace(
-# blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
-# )
-# result, err, _ = await blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
-#
-# @pytest.mark.asyncio
-# async def test_empty_sub_slots_epoch(self, empty_blockchain):
-# # 2m
-# # Tests adding an empty sub slot after the sub-epoch / epoch.
-# # Also tests overflow block in epoch
-# blocks_base = bt.get_consecutive_blocks(test_constants.EPOCH_SUB_BLOCKS)
-# blocks_1 = bt.get_consecutive_blocks(1, block_list_input=blocks_base, force_overflow=True)
-# blocks_2 = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks_base, force_overflow=True)
-# blocks_3 = bt.get_consecutive_blocks(1, skip_slots=2, block_list_input=blocks_base, force_overflow=True)
-# blocks_4 = bt.get_consecutive_blocks(1, block_list_input=blocks_base)
-# for block in blocks_base:
-# result, err, _ = await empty_blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-# for block in [blocks_1[-1], blocks_2[-1], blocks_3[-1], blocks_4[-1]]:
-# result, err, _ = await empty_blockchain.receive_block(block)
-# assert err is None
-#
-# @pytest.mark.asyncio
-# async def test_wrong_cc_hash_rc(self, empty_blockchain):
-# # 2o
-# blockchain = empty_blockchain
-# blocks = bt.get_consecutive_blocks(1, skip_slots=1)
-# blocks = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks)
-# assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# new_finished_ss = recursive_replace(
-# blocks[-1].finished_sub_slots[-1],
-# "reward_chain",
-# replace(blocks[-1].finished_sub_slots[-1].reward_chain, challenge_chain_sub_slot_hash=bytes([3] * 32)),
-# )
-# block_1_bad = recursive_replace(
-# blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
-# )
-#
-# result, err, _ = await blockchain.receive_block(block_1_bad)
-# assert result == ReceiveBlockResult.INVALID_BLOCK
-# assert err == Err.INVALID_CHALLENGE_SLOT_HASH_RC
-#
-# @pytest.mark.asyncio
-# async def test_invalid_cc_sub_slot_vdf(self, empty_blockchain):
-# # 2q
-# blocks = bt.get_consecutive_blocks(10)
-# for block in blocks:
-# if len(block.finished_sub_slots):
-# # Bad iters
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[-1],
-# "challenge_chain",
-# recursive_replace(
-# block.finished_sub_slots[-1].challenge_chain,
-# "challenge_chain_end_of_slot_vdf.number_of_iterations",
-# uint64(10000000),
-# ),
-# )
-# new_finished_ss = recursive_replace(
-# new_finished_ss,
-# "reward_chain.challenge_chain_sub_slot_hash",
-# new_finished_ss.challenge_chain.get_hash(),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_CC_EOS_VDF
-#
-# # Bad output
-# new_finished_ss_2 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "challenge_chain",
-# recursive_replace(
-# block.finished_sub_slots[-1].challenge_chain,
-# "challenge_chain_end_of_slot_vdf.output",
-# ClassgroupElement.get_default_element(),
-# ),
-# )
-#
-# new_finished_ss_2 = recursive_replace(
-# new_finished_ss_2,
-# "reward_chain.challenge_chain_sub_slot_hash",
-# new_finished_ss_2.challenge_chain.get_hash(),
-# )
-# block_bad_2 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_2)
-# assert err == Err.INVALID_CC_EOS_VDF
-#
-# # Bad challenge hash
-# new_finished_ss_3 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "challenge_chain",
-# recursive_replace(
-# block.finished_sub_slots[-1].challenge_chain,
-# "challenge_chain_end_of_slot_vdf.challenge",
-# bytes([1] * 32),
-# ),
-# )
-#
-# new_finished_ss_3 = recursive_replace(
-# new_finished_ss_3,
-# "reward_chain.challenge_chain_sub_slot_hash",
-# new_finished_ss_3.challenge_chain.get_hash(),
-# )
-# block_bad_3 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_3)
-# assert err == Err.INVALID_CC_EOS_VDF or err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
-#
-# # Bad proof
-# new_finished_ss_5 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "proofs.challenge_chain_slot_proof",
-# VDFProof(uint8(0), b"1239819023890"),
-# )
-# block_bad_5 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_5)
-# assert err == Err.INVALID_CC_EOS_VDF
-#
-# result, err, _ = await empty_blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_invalid_rc_sub_slot_vdf(self, empty_blockchain):
-# # 2p
-# blocks = bt.get_consecutive_blocks(10)
-# for block in blocks:
-# if len(block.finished_sub_slots):
-# # Bad iters
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[-1],
-# "reward_chain",
-# recursive_replace(
-# block.finished_sub_slots[-1].reward_chain,
-# "end_of_slot_vdf.number_of_iterations",
-# uint64(10000000),
-# ),
-# )
-# block_bad = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_RC_EOS_VDF
-#
-# # Bad output
-# new_finished_ss_2 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "reward_chain",
-# recursive_replace(
-# block.finished_sub_slots[-1].reward_chain,
-# "end_of_slot_vdf.output",
-# ClassgroupElement.get_default_element(),
-# ),
-# )
-# block_bad_2 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_2)
-# assert err == Err.INVALID_RC_EOS_VDF
-#
-# # Bad challenge hash
-# new_finished_ss_3 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "reward_chain",
-# recursive_replace(
-# block.finished_sub_slots[-1].reward_chain,
-# "end_of_slot_vdf.challenge",
-# bytes([1] * 32),
-# ),
-# )
-# block_bad_3 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_3)
-# assert err == Err.INVALID_RC_EOS_VDF
-#
-# # Bad proof
-# new_finished_ss_5 = recursive_replace(
-# block.finished_sub_slots[-1],
-# "proofs.reward_chain_slot_proof",
-# VDFProof(uint8(0), b"1239819023890"),
-# )
-# block_bad_5 = recursive_replace(
-# block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad_5)
-# assert err == Err.INVALID_RC_EOS_VDF
-#
-# result, err, _ = await empty_blockchain.receive_block(block)
-# assert err is None
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_genesis_bad_deficit(self, empty_blockchain):
-# # 2r
-# block = bt.get_consecutive_blocks(1, skip_slots=2)[0]
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[-1],
-# "reward_chain",
-# recursive_replace(
-# block.finished_sub_slots[-1].reward_chain,
-# "deficit",
-# test_constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK - 1,
-# ),
-# )
-# block_bad = recursive_replace(block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss])
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_DEFICIT
-#
-# @pytest.mark.asyncio
-# async def test_reset_deficit(self, empty_blockchain):
-# # 2s, 2t
-# blockchain = empty_blockchain
-# blocks = bt.get_consecutive_blocks(2)
-# await empty_blockchain.receive_block(blocks[0])
-# await empty_blockchain.receive_block(blocks[1])
-# case_1, case_2 = False, False
-# while not case_1 or not case_2:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
-# if len(blocks[-1].finished_sub_slots) > 0:
-# new_finished_ss = recursive_replace(
-# blocks[-1].finished_sub_slots[-1],
-# "reward_chain",
-# recursive_replace(
-# blocks[-1].finished_sub_slots[-1].reward_chain,
-# "deficit",
-# uint8(0),
-# ),
-# )
-# if blockchain.sub_blocks[blocks[-2].header_hash].deficit == 0:
-# case_1 = True
-# else:
-# case_2 = True
-#
-# block_bad = recursive_replace(
-# blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_DEFICIT or err == Err.INVALID_ICC_HASH_CC
-#
-# result, err, _ = await empty_blockchain.receive_block(blocks[-1])
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_genesis_has_ses(self, empty_blockchain):
-# # 3a
-# block = bt.get_consecutive_blocks(1, skip_slots=1)[0]
-# new_finished_ss = recursive_replace(
-# block.finished_sub_slots[0],
-# "challenge_chain",
-# recursive_replace(
-# block.finished_sub_slots[0].challenge_chain,
-# "subepoch_summary_hash",
-# bytes([0] * 32),
-# ),
-# )
-#
-# new_finished_ss = recursive_replace(
-# new_finished_ss,
-# "reward_chain",
-# replace(
-# new_finished_ss.reward_chain, challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash()
-# ),
-# )
-# block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:])
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
-#
-# @pytest.mark.asyncio
-# async def test_no_ses_if_no_se(self, empty_blockchain):
-# # 3b
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if len(blocks[-1].finished_sub_slots) > 0:
-# new_finished_ss: EndOfSubSlotBundle = recursive_replace(
-# blocks[-1].finished_sub_slots[0],
-# "challenge_chain",
-# recursive_replace(
-# blocks[-1].finished_sub_slots[0].challenge_chain,
-# "subepoch_summary_hash",
-# bytes([0] * 32),
-# ),
-# )
-#
-# new_finished_ss = recursive_replace(
-# new_finished_ss,
-# "reward_chain",
-# replace(
-# new_finished_ss.reward_chain,
-# challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash(),
-# ),
-# )
-# block_bad = recursive_replace(
-# blocks[-1], "finished_sub_slots", [new_finished_ss] + blocks[-1].finished_sub_slots[1:]
-# )
-# result, err, _ = await empty_blockchain.receive_block(block_bad)
-# assert err == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
-# return
-# await empty_blockchain.receive_block(blocks[-1])
-#
-# @pytest.mark.asyncio
-# async def test_too_many_sub_blocks(self, empty_blockchain):
-# # 4: TODO
-# pass
-#
-# @pytest.mark.asyncio
-# async def test_bad_pos(self, empty_blockchain):
-# # 5
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.proof_of_space.challenge", std_hash(b""))
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
-#
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.proof_of_space.pool_contract_puzzle_hash", std_hash(b"")
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
-#
-# block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.proof_of_space.pool_public_key", None)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
-#
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.proof_of_space.plot_public_key",
-# AugSchemeMPL.key_gen(std_hash(b"1231n")).get_g1(),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.proof_of_space.size",
-# 32,
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.proof_of_space.proof",
-# bytes([1] * int(blocks[-1].reward_chain_sub_block.proof_of_space.size * 64 / 8)),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
-#
-# # TODO: test not passing the plot filter
-#
-# @pytest.mark.asyncio
-# async def test_bad_signage_point_index(self, empty_blockchain):
-# # 6
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# with raises(ValueError):
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.signage_point_index", test_constants.NUM_SPS_SUB_SLOT
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_SP_INDEX
-# with raises(ValueError):
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.signage_point_index", test_constants.NUM_SPS_SUB_SLOT + 1
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_SP_INDEX
-#
-# @pytest.mark.asyncio
-# async def test_sp_0_no_sp(self, empty_blockchain):
-# # 7
-# blocks = []
-# case_1, case_2 = False, False
-# while not case_1 or not case_2:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].reward_chain_sub_block.signage_point_index == 0:
-# case_1 = True
-# block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.signage_point_index", uint8(1))
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_SP_INDEX
-# else:
-# case_2 = True
-# block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.signage_point_index", uint8(0))
-# error_code = (await empty_blockchain.receive_block(block_bad))[1]
-# assert error_code == Err.INVALID_SP_INDEX or error_code == Err.INVALID_POSPACE
-# assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_epoch_overflows(self, empty_blockchain):
-# # 9. TODO. This is hard to test because it requires modifying the block tools to make these special blocks
-# pass
-#
-# @pytest.mark.asyncio
-# async def test_bad_total_iters(self, empty_blockchain):
-# # 10
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.total_iters", blocks[-1].reward_chain_sub_block.total_iters + 1
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_TOTAL_ITERS
-#
-# @pytest.mark.asyncio
-# async def test_bad_rc_sp_vdf(self, empty_blockchain):
-# # 11
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].reward_chain_sub_block.signage_point_index != 0:
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.reward_chain_sp_vdf.challenge", std_hash(b"1")
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.reward_chain_sp_vdf.output",
-# ClassgroupElement(int512(10), int512(2)),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.reward_chain_sp_vdf.number_of_iterations",
-# uint64(1111111111111),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sp_proof",
-# VDFProof(uint8(0), std_hash(b"")),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
-# return
-# assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_bad_rc_sp_sig(self, empty_blockchain):
-# # 12
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.reward_chain_sp_signature", G2Element.generator()
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SIGNATURE
-#
-# @pytest.mark.asyncio
-# async def test_bad_cc_sp_vdf(self, empty_blockchain):
-# # 13. Note: does not validate fully due to proof of space being validated first
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].reward_chain_sub_block.signage_point_index != 0:
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.challenge_chain_sp_vdf.challenge", std_hash(b"1")
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[0] == ReceiveBlockResult.INVALID_BLOCK
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.challenge_chain_sp_vdf.output",
-# ClassgroupElement(int512(10), int512(2)),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[0] == ReceiveBlockResult.INVALID_BLOCK
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.challenge_chain_sp_vdf.number_of_iterations",
-# uint64(1111111111111),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[0] == ReceiveBlockResult.INVALID_BLOCK
-# block_bad = recursive_replace(
-# blocks[-1],
-# "challenge_chain_sp_proof",
-# VDFProof(uint8(0), std_hash(b"")),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_SP_VDF
-# return
-# assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_bad_cc_sp_sig(self, empty_blockchain):
-# # 14
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.challenge_chain_sp_signature", G2Element.generator()
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_SIGNATURE
-#
-# @pytest.mark.asyncio
-# async def test_is_block(self, empty_blockchain):
-# # 15: TODO
-# pass
-#
-# @pytest.mark.asyncio
-# async def test_bad_foliage_sb_sig(self, empty_blockchain):
-# # 16
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_sub_block_signature", G2Element.generator()
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PLOT_SIGNATURE
-#
-# @pytest.mark.asyncio
-# async def test_bad_foliage_block_sig(self, empty_blockchain):
-# # 17
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].foliage_block is not None:
-# block_bad = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_block_signature", G2Element.generator()
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PLOT_SIGNATURE
-# return
-# assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# @pytest.mark.asyncio
-# async def test_unfinished_reward_chain_sb_hash(self, empty_blockchain):
-# # 18
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_sub_block_data.unfinished_reward_block_hash", std_hash(b"2")
-# )
-# new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
-# new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_URSB_HASH
-#
-# @pytest.mark.asyncio
-# async def test_pool_target_height(self, empty_blockchain):
-# # 19
-# blocks = bt.get_consecutive_blocks(3)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# assert (await empty_blockchain.receive_block(blocks[1]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_sub_block_data.pool_target.max_height", 1
-# )
-# new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
-# new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.OLD_POOL_TARGET
-#
-# @pytest.mark.asyncio
-# async def test_pool_target_pre_farm(self, empty_blockchain):
-# # 20a
-# blocks = bt.get_consecutive_blocks(1)
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_sub_block_data.pool_target.puzzle_hash", std_hash(b"12")
-# )
-# new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
-# new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREFARM
-#
-# @pytest.mark.asyncio
-# async def test_pool_target_signature(self, empty_blockchain):
-# # 20b
-# blocks = bt.get_consecutive_blocks(3)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# assert (await empty_blockchain.receive_block(blocks[1]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_sub_block_data.pool_signature", G2Element.generator()
-# )
-# new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
-# new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POOL_SIGNATURE
-#
-# @pytest.mark.asyncio
-# async def test_foliage_data_presence(self, empty_blockchain):
-# # 22
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# case_1, case_2 = False, False
-# while not case_1 or not case_2:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].foliage_block is not None:
-# case_1 = True
-# block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_sub_block.foliage_block_hash", None)
-# else:
-# case_2 = True
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_block_hash", std_hash(b"")
-# )
-# err_code = (await empty_blockchain.receive_block(block_bad))[1]
-# assert err_code == Err.INVALID_FOLIAGE_BLOCK_PRESENCE or err_code == Err.INVALID_IS_BLOCK
-# await empty_blockchain.receive_block(blocks[-1])
-#
-# @pytest.mark.asyncio
-# async def test_foliage_block_hash(self, empty_blockchain):
-# # 23
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# case_1, case_2 = False, False
-# while not case_1 or not case_2:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].foliage_block is not None:
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_sub_block.foliage_block_hash", std_hash(b"2")
-# )
-#
-# new_m = block_bad.foliage_sub_block.foliage_block_hash
-# new_fbh_sig = bt.get_plot_signature(
-# new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
-# )
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_FOLIAGE_BLOCK_HASH
-# return
-# await empty_blockchain.receive_block(blocks[-1])
-#
-# @pytest.mark.asyncio
-# async def test_genesis_bad_prev_block(self, empty_blockchain):
-# # 24a
-# blocks = bt.get_consecutive_blocks(1)
-# block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.prev_block_hash", std_hash(b"2"))
-# block_bad: FullBlock = recursive_replace(
-# block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
-# )
-# new_m = block_bad.foliage_sub_block.foliage_block_hash
-# new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREV_BLOCK_HASH
-#
-# @pytest.mark.asyncio
-# async def test_bad_prev_block_non_genesis(self, empty_blockchain):
-# # 24b
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].foliage_block is not None:
-# block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.prev_block_hash", std_hash(b"2"))
-# block_bad: FullBlock = recursive_replace(
-# block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
-# )
-# new_m = block_bad.foliage_sub_block.foliage_block_hash
-# new_fbh_sig = bt.get_plot_signature(
-# new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
-# )
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREV_BLOCK_HASH
-# return
-# await empty_blockchain.receive_block(blocks[-1])
-#
-# @pytest.mark.asyncio
-# async def test_bad_filter_hash(self, empty_blockchain):
-# # 25
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].foliage_block is not None:
-# block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.filter_hash", std_hash(b"2"))
-# block_bad: FullBlock = recursive_replace(
-# block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
-# )
-# new_m = block_bad.foliage_sub_block.foliage_block_hash
-# new_fbh_sig = bt.get_plot_signature(
-# new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
-# )
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_TRANSACTIONS_FILTER_HASH
-# return
-# await empty_blockchain.receive_block(blocks[-1])
-#
-# @pytest.mark.asyncio
-# async def test_bad_timestamp(self, empty_blockchain):
-# # 26
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if blocks[-1].foliage_block is not None:
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_block.timestamp", blocks[0].foliage_block.timestamp - 10
-# )
-# block_bad: FullBlock = recursive_replace(
-# block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
-# )
-# new_m = block_bad.foliage_sub_block.foliage_block_hash
-# new_fbh_sig = bt.get_plot_signature(
-# new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
-# )
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.TIMESTAMP_TOO_FAR_IN_PAST
-#
-# block_bad: FullBlock = recursive_replace(
-# blocks[-1], "foliage_block.timestamp", blocks[0].foliage_block.timestamp + 10000000
-# )
-# block_bad: FullBlock = recursive_replace(
-# block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
-# )
-# new_m = block_bad.foliage_sub_block.foliage_block_hash
-# new_fbh_sig = bt.get_plot_signature(
-# new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
-# )
-# block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.TIMESTAMP_TOO_FAR_IN_FUTURE
-# return
-# await empty_blockchain.receive_block(blocks[-1])
-#
-# @pytest.mark.asyncio
-# async def test_sub_block_height(self, empty_blockchain):
-# # 27
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.sub_block_height", 2)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_HEIGHT
-#
-# @pytest.mark.asyncio
-# async def test_sub_block_height_genesis(self, empty_blockchain):
-# # 27
-# blocks = bt.get_consecutive_blocks(1)
-# block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.sub_block_height", 1)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREV_BLOCK_HASH
-#
-# @pytest.mark.asyncio
-# async def test_weight(self, empty_blockchain):
-# # 28
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.weight", 22131)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_WEIGHT
-#
-# @pytest.mark.asyncio
-# async def test_weight_genesis(self, empty_blockchain):
-# # 28
-# blocks = bt.get_consecutive_blocks(1)
-# block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.weight", 0)
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_WEIGHT
-#
-# @pytest.mark.asyncio
-# async def test_bad_cc_ip_vdf(self, empty_blockchain):
-# # 29
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.challenge_chain_ip_vdf.challenge", std_hash(b"1")
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.challenge_chain_ip_vdf.output",
-# ClassgroupElement(int512(10), int512(2)),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.challenge_chain_ip_vdf.number_of_iterations",
-# uint64(1111111111111),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "challenge_chain_ip_proof",
-# VDFProof(uint8(0), std_hash(b"")),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
-#
-# @pytest.mark.asyncio
-# async def test_bad_rc_ip_vdf(self, empty_blockchain):
-# # 30
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.reward_chain_ip_vdf.challenge", std_hash(b"1")
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.reward_chain_ip_vdf.output",
-# ClassgroupElement(int512(10), int512(2)),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.reward_chain_ip_vdf.number_of_iterations",
-# uint64(1111111111111),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_ip_proof",
-# VDFProof(uint8(0), std_hash(b"")),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
-#
-# @pytest.mark.asyncio
-# async def test_bad_icc_ip_vdf(self, empty_blockchain):
-# # 31
-# blocks = bt.get_consecutive_blocks(1)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# block_bad = recursive_replace(
-# blocks[-1], "reward_chain_sub_block.infused_challenge_chain_ip_vdf.challenge", std_hash(b"1")
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.infused_challenge_chain_ip_vdf.output",
-# ClassgroupElement(int512(10), int512(2)),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "reward_chain_sub_block.infused_challenge_chain_ip_vdf.number_of_iterations",
-# uint64(1111111111111),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
-# block_bad = recursive_replace(
-# blocks[-1],
-# "infused_challenge_chain_ip_proof",
-# VDFProof(uint8(0), std_hash(b"")),
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
-#
-# @pytest.mark.asyncio
-# async def test_reward_block_hash(self, empty_blockchain):
-# # 32
-# blocks = bt.get_consecutive_blocks(2)
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-# block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_sub_block.reward_block_hash", std_hash(b""))
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_REWARD_BLOCK_HASH
-#
-# @pytest.mark.asyncio
-# async def test_reward_block_hash_2(self, empty_blockchain):
-# # 33
-# blocks = bt.get_consecutive_blocks(1)
-# block_bad: FullBlock = recursive_replace(blocks[0], "reward_chain_sub_block.is_block", False)
-# block_bad: FullBlock = recursive_replace(
-# block_bad, "foliage_sub_block.reward_block_hash", block_bad.reward_chain_sub_block.get_hash()
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_FOLIAGE_BLOCK_PRESENCE
-# assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-# # Test one which should not be a block
-# while True:
-# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
-# if not blocks[-1].is_block():
-# block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.is_block", True)
-# block_bad: FullBlock = recursive_replace(
-# block_bad, "foliage_sub_block.reward_block_hash", block_bad.reward_chain_sub_block.get_hash()
-# )
-# assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_FOLIAGE_BLOCK_PRESENCE
-# return
-# assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
-#
-#
-# class TestBodyValidation:
-# @pytest.mark.asyncio
-# async def test_not_block_but_has_data(self, empty_blockchain):
-# # TODO
-# pass
-#
-#
-# class TestReorgs:
-# @pytest.mark.asyncio
-# async def test_basic_reorg(self, empty_blockchain):
-# b = empty_blockchain
-# blocks = bt.get_consecutive_blocks(15)
-#
-# for block in blocks:
-# assert (await b.receive_block(block))[0] == ReceiveBlockResult.NEW_PEAK
-# assert b.get_peak().sub_block_height == 14
-#
-# blocks_reorg_chain = bt.get_consecutive_blocks(7, blocks[:10], seed=b"2")
-# for reorg_block in blocks_reorg_chain:
-# result, error_code, fork_height = await b.receive_block(reorg_block)
-# if reorg_block.sub_block_height < 10:
-# assert result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
-# elif reorg_block.sub_block_height < 14:
-# assert result == ReceiveBlockResult.ADDED_AS_ORPHAN
-# elif reorg_block.sub_block_height >= 15:
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert error_code is None
-# assert b.get_peak().sub_block_height == 16
-#
-# @pytest.mark.asyncio
-# async def test_long_reorg(self, empty_blockchain):
-# # Reorg longer than a difficulty adjustment
-# # Also tests higher weight chain but lower height
-# b = empty_blockchain
-# num_blocks_chain_1 = 3 * test_constants.EPOCH_SUB_BLOCKS + test_constants.MAX_SUB_SLOT_SUB_BLOCKS + 10
-# num_blocks_chain_2_start = test_constants.EPOCH_SUB_BLOCKS - 20
-# num_blocks_chain_2 = 3 * test_constants.EPOCH_SUB_BLOCKS + test_constants.MAX_SUB_SLOT_SUB_BLOCKS + 8
-#
-# blocks = bt.get_consecutive_blocks(num_blocks_chain_1)
-#
-# for block in blocks:
-# assert (await b.receive_block(block))[0] == ReceiveBlockResult.NEW_PEAK
-# chain_1_height = b.get_peak().sub_block_height
-# chain_1_weight = b.get_peak().weight
-# assert chain_1_height == (num_blocks_chain_1 - 1)
-#
-# # These blocks will have less time between them (timestamp) and therefore will make difficulty go up
-# # This means that the weight will grow faster, and we can get a heavier chain with lower height
-# blocks_reorg_chain = bt.get_consecutive_blocks(
-# num_blocks_chain_2 - num_blocks_chain_2_start,
-# blocks[:num_blocks_chain_2_start],
-# seed=b"2",
-# time_per_sub_block=8,
-# )
-# found_orphan = False
-# for reorg_block in blocks_reorg_chain:
-# result, error_code, fork_height = await b.receive_block(reorg_block)
-# if reorg_block.sub_block_height < num_blocks_chain_2_start:
-# assert result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
-# if reorg_block.weight <= chain_1_weight:
-# if result == ReceiveBlockResult.ADDED_AS_ORPHAN:
-# found_orphan = True
-# assert error_code is None
-# assert result == ReceiveBlockResult.ADDED_AS_ORPHAN or result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
-# elif reorg_block.weight > chain_1_weight:
-# assert reorg_block.sub_block_height < chain_1_height
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert error_code is None
-# assert found_orphan
-#
-# assert b.get_peak().weight > chain_1_weight
-# assert b.get_peak().sub_block_height < chain_1_height
-#
-# @pytest.mark.asyncio
-# async def test_reorg_from_genesis(self, empty_blockchain):
-# b = empty_blockchain
-# blocks = bt.get_consecutive_blocks(15)
-#
-# for block in blocks:
-# assert (await b.receive_block(block))[0] == ReceiveBlockResult.NEW_PEAK
-# assert b.get_peak().sub_block_height == 14
-#
-# # Reorg to alternate chain that is 1 height longer
-# found_orphan = False
-# blocks_reorg_chain = bt.get_consecutive_blocks(16, [], seed=b"2")
-# for reorg_block in blocks_reorg_chain:
-# result, error_code, fork_height = await b.receive_block(reorg_block)
-# print(reorg_block.sub_block_height, result)
-# if reorg_block.sub_block_height < 14:
-# if result == ReceiveBlockResult.ADDED_AS_ORPHAN:
-# found_orphan = True
-# assert result == ReceiveBlockResult.ADDED_AS_ORPHAN or result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
-# elif reorg_block.sub_block_height >= 15:
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert error_code is None
-#
-# # Back to original chain
-# blocks_reorg_chain_2 = bt.get_consecutive_blocks(3, blocks, seed=b"3")
-#
-# result, error_code, fork_height = await b.receive_block(blocks_reorg_chain_2[-3])
-# assert result == ReceiveBlockResult.ADDED_AS_ORPHAN
-#
-# result, error_code, fork_height = await b.receive_block(blocks_reorg_chain_2[-2])
-# assert result == ReceiveBlockResult.NEW_PEAK
-#
-# result, error_code, fork_height = await b.receive_block(blocks_reorg_chain_2[-1])
-# assert result == ReceiveBlockResult.NEW_PEAK
-# assert found_orphan
-# assert b.get_peak().sub_block_height == 17
+ @pytest.mark.asyncio
+ async def test_overflow_genesis(self, empty_blockchain):
+ genesis = bt.get_consecutive_blocks(1, force_overflow=True)[0]
+ result, err, _ = await empty_blockchain.receive_block(genesis, False)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_genesis_empty_slots(self, empty_blockchain):
+ genesis = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=3)[0]
+ result, err, _ = await empty_blockchain.receive_block(genesis, False)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_overflow_genesis_empty_slots(self, empty_blockchain):
+ genesis = bt.get_consecutive_blocks(1, force_overflow=True, skip_slots=3)[0]
+ result, err, _ = await empty_blockchain.receive_block(genesis, False)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_genesis_validate_1(self, empty_blockchain):
+ genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
+ bad_prev = bytes([1] * 32)
+ genesis = recursive_replace(genesis, "foliage_sub_block.prev_sub_block_hash", bad_prev)
+ result, err, _ = await empty_blockchain.receive_block(genesis, False)
+ assert err == Err.INVALID_PREV_BLOCK_HASH
+
+
+class TestBlockHeaderValidation:
+ @pytest.mark.asyncio
+ async def test_long_chain(self, empty_blockchain, default_1000_blocks):
+ blocks = default_1000_blocks
+ for block in blocks:
+ if (
+ len(block.finished_sub_slots) > 0
+ and block.finished_sub_slots[0].challenge_chain.subepoch_summary_hash is not None
+ ):
+ # Sub/Epoch. Try using a bad ssi and difficulty to test 2m and 2n
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[0],
+ "challenge_chain.new_sub_slot_iters",
+ uint64(10000000),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_NEW_SUB_SLOT_ITERS
+ new_finished_ss_2 = recursive_replace(
+ block.finished_sub_slots[0],
+ "challenge_chain.new_difficulty",
+ uint64(10000000),
+ )
+ block_bad_2 = recursive_replace(
+ block, "finished_sub_slots", [new_finished_ss_2] + block.finished_sub_slots[1:]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_2)
+ assert err == Err.INVALID_NEW_DIFFICULTY
+
+ # 3c
+ new_finished_ss_3: EndOfSubSlotBundle = recursive_replace(
+ block.finished_sub_slots[0],
+ "challenge_chain.subepoch_summary_hash",
+ bytes([0] * 32),
+ )
+ new_finished_ss_3 = recursive_replace(
+ new_finished_ss_3,
+ "reward_chain.challenge_chain_sub_slot_hash",
+ new_finished_ss_3.challenge_chain.get_hash(),
+ )
+ block_bad_3 = recursive_replace(
+ block, "finished_sub_slots", [new_finished_ss_3] + block.finished_sub_slots[1:]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_3)
+ assert err == Err.INVALID_SUB_EPOCH_SUMMARY
+
+ # 3d
+ new_finished_ss_4 = recursive_replace(
+ block.finished_sub_slots[0],
+ "challenge_chain.subepoch_summary_hash",
+ None,
+ )
+ new_finished_ss_4 = recursive_replace(
+ new_finished_ss_4,
+ "reward_chain.challenge_chain_sub_slot_hash",
+ new_finished_ss_4.challenge_chain.get_hash(),
+ )
+ block_bad_4 = recursive_replace(
+ block, "finished_sub_slots", [new_finished_ss_4] + block.finished_sub_slots[1:]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_4)
+ assert err == Err.INVALID_SUB_EPOCH_SUMMARY or err == Err.INVALID_NEW_SUB_SLOT_ITERS
+
+ result, err, _ = await empty_blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+ log.info(
+ f"Added block {block.sub_block_height} total iters {block.total_iters} "
+ f"new slot? {len(block.finished_sub_slots)}"
+ )
+ assert empty_blockchain.get_peak().sub_block_height == len(blocks) - 1
+
+ @pytest.mark.asyncio
+ async def test_unfinished_blocks(self, empty_blockchain):
+ blockchain = empty_blockchain
+ blocks = bt.get_consecutive_blocks(2)
+ for block in blocks[:-1]:
+ result, err, _ = await blockchain.receive_block(block)
+ assert result == ReceiveBlockResult.NEW_PEAK
+ block = blocks[-1]
+ unf = UnfinishedBlock(
+ block.finished_sub_slots,
+ block.reward_chain_sub_block.get_unfinished(),
+ block.challenge_chain_sp_proof,
+ block.reward_chain_sp_proof,
+ block.foliage_sub_block,
+ block.foliage_block,
+ block.transactions_info,
+ block.transactions_generator,
+ )
+ _, err = await blockchain.validate_unfinished_block(unf, False)
+ assert err is None
+ result, err, _ = await blockchain.receive_block(block)
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
+ block = blocks[-1]
+ unf = UnfinishedBlock(
+ block.finished_sub_slots,
+ block.reward_chain_sub_block.get_unfinished(),
+ block.challenge_chain_sp_proof,
+ block.reward_chain_sp_proof,
+ block.foliage_sub_block,
+ block.foliage_block,
+ block.transactions_info,
+ block.transactions_generator,
+ )
+ _, err = await blockchain.validate_unfinished_block(unf, False)
+ assert err is None
+
+ @pytest.mark.asyncio
+ async def test_empty_genesis(self, empty_blockchain):
+ blockchain = empty_blockchain
+ for block in bt.get_consecutive_blocks(2, skip_slots=3):
+ result, err, _ = await blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_empty_slots_non_genesis(self, empty_blockchain):
+ blockchain = empty_blockchain
+ blocks = bt.get_consecutive_blocks(10)
+ for block in blocks:
+ result, err, _ = await blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ blocks = bt.get_consecutive_blocks(10, skip_slots=2, block_list_input=blocks)
+ for block in blocks[10:]:
+ result, err, _ = await blockchain.receive_block(block)
+ assert err is None
+ assert blockchain.get_peak().sub_block_height == 19
+
+ @pytest.mark.asyncio
+ async def test_one_sb_per_slot(self, empty_blockchain):
+ blockchain = empty_blockchain
+ num_blocks = 20
+ blocks = []
+ for i in range(num_blocks):
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
+ result, err, _ = await blockchain.receive_block(blocks[-1])
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert blockchain.get_peak().sub_block_height == num_blocks - 1
+
+ @pytest.mark.asyncio
+ async def test_one_sb_per_two_slots(self, empty_blockchain):
+ blockchain = empty_blockchain
+ num_blocks = 20
+ blocks = []
+ for i in range(num_blocks): # Same thing, but 2 sub-slots per sub-block
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2)
+ result, err, _ = await blockchain.receive_block(blocks[-1])
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert blockchain.get_peak().sub_block_height == num_blocks - 1
+
+ @pytest.mark.asyncio
+ async def test_one_sb_per_five_slots(self, empty_blockchain):
+ blockchain = empty_blockchain
+ num_blocks = 10
+ blocks = []
+ for i in range(num_blocks): # Same thing, but 5 sub-slots per sub-block
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=5)
+ result, err, _ = await blockchain.receive_block(blocks[-1])
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert blockchain.get_peak().sub_block_height == num_blocks - 1
+
+ @pytest.mark.asyncio
+ async def test_basic_chain_overflow(self, empty_blockchain):
+ blocks = bt.get_consecutive_blocks(5, force_overflow=True)
+ for block in blocks:
+ result, err, _ = await empty_blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert empty_blockchain.get_peak().sub_block_height == len(blocks) - 1
+
+ @pytest.mark.asyncio
+ async def test_one_sb_per_two_slots_force_overflow(self, empty_blockchain):
+ blockchain = empty_blockchain
+ num_blocks = 10
+ blocks = []
+ for i in range(num_blocks):
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2, force_overflow=True)
+ result, err, _ = await blockchain.receive_block(blocks[-1])
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert blockchain.get_peak().sub_block_height == num_blocks - 1
+
+ @pytest.mark.asyncio
+ async def test_invalid_prev(self, empty_blockchain):
+ # 1
+ blocks = bt.get_consecutive_blocks(2, force_overflow=False)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_1_bad = recursive_replace(blocks[-1], "foliage_sub_block.prev_sub_block_hash", bytes([0] * 32))
+
+ result, err, _ = await empty_blockchain.receive_block(block_1_bad)
+ assert result == ReceiveBlockResult.DISCONNECTED_BLOCK
+
+ @pytest.mark.asyncio
+ async def test_invalid_pospace(self, empty_blockchain):
+ # 2
+ blocks = bt.get_consecutive_blocks(2, force_overflow=False)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_1_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.proof_of_space.proof", bytes([0] * 32))
+
+ result, err, _ = await empty_blockchain.receive_block(block_1_bad)
+ assert result == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.INVALID_POSPACE
+
+ @pytest.mark.asyncio
+ async def test_invalid_sub_slot_challenge_hash_genesis(self, empty_blockchain):
+ # 2a
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
+ new_finished_ss = recursive_replace(
+ blocks[0].finished_sub_slots[0],
+ "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
+ bytes([2] * 32),
+ )
+ block_0_bad = recursive_replace(
+ blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
+ )
+
+ result, err, _ = await empty_blockchain.receive_block(block_0_bad)
+ assert result == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
+
+ @pytest.mark.asyncio
+ async def test_invalid_sub_slot_challenge_hash_non_genesis(self, empty_blockchain):
+ # 2b
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1, block_list_input=blocks)
+ new_finished_ss = recursive_replace(
+ blocks[1].finished_sub_slots[0],
+ "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
+ bytes([2] * 32),
+ )
+ block_1_bad = recursive_replace(
+ blocks[1], "finished_sub_slots", [new_finished_ss] + blocks[1].finished_sub_slots[1:]
+ )
+
+ _, _, _ = await empty_blockchain.receive_block(blocks[0])
+ result, err, _ = await empty_blockchain.receive_block(block_1_bad)
+ assert result == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
+
+ @pytest.mark.asyncio
+ async def test_invalid_sub_slot_challenge_hash_empty_ss(self, empty_blockchain):
+ # 2c
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=2, block_list_input=blocks)
+ new_finished_ss = recursive_replace(
+ blocks[1].finished_sub_slots[-1],
+ "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
+ bytes([2] * 32),
+ )
+ block_1_bad = recursive_replace(
+ blocks[1], "finished_sub_slots", blocks[1].finished_sub_slots[:-1] + [new_finished_ss]
+ )
+
+ _, _, _ = await empty_blockchain.receive_block(blocks[0])
+ result, err, _ = await empty_blockchain.receive_block(block_1_bad)
+ assert result == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
+
+ @pytest.mark.asyncio
+ async def test_genesis_no_icc(self, empty_blockchain):
+ # 2d
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
+ new_finished_ss = recursive_replace(
+ blocks[0].finished_sub_slots[0],
+ "infused_challenge_chain",
+ InfusedChallengeChainSubSlot(
+ VDFInfo(
+ bytes([0] * 32),
+ uint64(1200),
+ ClassgroupElement.get_default_element(),
+ )
+ ),
+ )
+ block_0_bad = recursive_replace(
+ blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
+ )
+
+ result, err, _ = await empty_blockchain.receive_block(block_0_bad)
+ assert result == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.SHOULD_NOT_HAVE_ICC
+
+ @pytest.mark.asyncio
+ async def test_invalid_icc_sub_slot_vdf(self, empty_blockchain):
+ blocks = bt.get_consecutive_blocks(10)
+ for block in blocks:
+ if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is not None:
+ # Bad iters
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[-1],
+ "infused_challenge_chain",
+ InfusedChallengeChainSubSlot(
+ replace(
+ block.finished_sub_slots[
+ -1
+ ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf,
+ number_of_iterations=10000000,
+ )
+ ),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_ICC_EOS_VDF
+
+ # Bad output
+ new_finished_ss_2 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "infused_challenge_chain",
+ InfusedChallengeChainSubSlot(
+ replace(
+ block.finished_sub_slots[
+ -1
+ ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf,
+ output=ClassgroupElement.get_default_element(),
+ )
+ ),
+ )
+ block_bad_2 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_2)
+ assert err == Err.INVALID_ICC_EOS_VDF
+
+ # Bad challenge hash
+ new_finished_ss_3 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "infused_challenge_chain",
+ InfusedChallengeChainSubSlot(
+ replace(
+ block.finished_sub_slots[
+ -1
+ ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf,
+ challenge=bytes([0] * 32),
+ )
+ ),
+ )
+ block_bad_3 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_3)
+ assert err == Err.INVALID_ICC_EOS_VDF
+
+ # Bad proof
+ new_finished_ss_5 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "proofs.infused_challenge_chain_slot_proof",
+ VDFProof(uint8(0), b"1239819023890"),
+ )
+ block_bad_5 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_5)
+ assert err == Err.INVALID_ICC_EOS_VDF
+
+ result, err, _ = await empty_blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_invalid_icc_into_cc(self, empty_blockchain):
+ blockchain = empty_blockchain
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ case_1, case_2 = False, False
+ while not case_1 or not case_2:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
+ block = blocks[-1]
+ if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is not None:
+ if (
+ block.finished_sub_slots[-1].reward_chain.deficit
+ == test_constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK
+ ):
+ # 2g
+ case_1 = True
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[-1],
+ "challenge_chain",
+ replace(
+ block.finished_sub_slots[-1].challenge_chain,
+ infused_challenge_chain_sub_slot_hash=bytes([1] * 32),
+ ),
+ )
+ else:
+ # 2h
+ case_2 = True
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[-1],
+ "challenge_chain",
+ replace(
+ block.finished_sub_slots[-1].challenge_chain,
+ infused_challenge_chain_sub_slot_hash=block.finished_sub_slots[
+ -1
+ ].infused_challenge_chain.get_hash(),
+ ),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
+ )
+ result, err, _ = await blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_ICC_HASH_CC
+
+ # 2i
+ new_finished_ss_bad_rc = recursive_replace(
+ block.finished_sub_slots[-1],
+ "reward_chain",
+ replace(block.finished_sub_slots[-1].reward_chain, infused_challenge_chain_sub_slot_hash=None),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
+ )
+ result, err, _ = await blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_ICC_HASH_RC
+ elif len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is None:
+ # 2j
+ new_finished_ss_bad_cc = recursive_replace(
+ block.finished_sub_slots[-1],
+ "challenge_chain",
+ replace(
+ block.finished_sub_slots[-1].challenge_chain,
+ infused_challenge_chain_sub_slot_hash=bytes([1] * 32),
+ ),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_cc]
+ )
+ result, err, _ = await blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_ICC_HASH_CC
+
+ # 2k
+ new_finished_ss_bad_rc = recursive_replace(
+ block.finished_sub_slots[-1],
+ "reward_chain",
+ replace(
+ block.finished_sub_slots[-1].reward_chain, infused_challenge_chain_sub_slot_hash=bytes([1] * 32)
+ ),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
+ )
+ result, err, _ = await blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_ICC_HASH_RC
+
+ # Finally, add the block properly
+ result, err, _ = await blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_empty_slot_no_ses(self, empty_blockchain):
+ # 2l
+ blockchain = empty_blockchain
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=4)
+
+ new_finished_ss = recursive_replace(
+ blocks[-1].finished_sub_slots[-1],
+ "challenge_chain",
+ replace(blocks[-1].finished_sub_slots[-1].challenge_chain, subepoch_summary_hash=std_hash(b"0")),
+ )
+ block_bad = recursive_replace(
+ blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
+ )
+ result, err, _ = await blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
+
+ @pytest.mark.asyncio
+ async def test_empty_sub_slots_epoch(self, empty_blockchain):
+ # 2m
+ # Tests adding an empty sub slot after the sub-epoch / epoch.
+ # Also tests overflow block in epoch
+ blocks_base = bt.get_consecutive_blocks(test_constants.EPOCH_SUB_BLOCKS)
+ blocks_1 = bt.get_consecutive_blocks(1, block_list_input=blocks_base, force_overflow=True)
+ blocks_2 = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks_base, force_overflow=True)
+ blocks_3 = bt.get_consecutive_blocks(1, skip_slots=2, block_list_input=blocks_base, force_overflow=True)
+ blocks_4 = bt.get_consecutive_blocks(1, block_list_input=blocks_base)
+ for block in blocks_base:
+ result, err, _ = await empty_blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+ for block in [blocks_1[-1], blocks_2[-1], blocks_3[-1], blocks_4[-1]]:
+ result, err, _ = await empty_blockchain.receive_block(block)
+ assert err is None
+
+ @pytest.mark.asyncio
+ async def test_wrong_cc_hash_rc(self, empty_blockchain):
+ # 2o
+ blockchain = empty_blockchain
+ blocks = bt.get_consecutive_blocks(1, skip_slots=1)
+ blocks = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks)
+ assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ new_finished_ss = recursive_replace(
+ blocks[-1].finished_sub_slots[-1],
+ "reward_chain",
+ replace(blocks[-1].finished_sub_slots[-1].reward_chain, challenge_chain_sub_slot_hash=bytes([3] * 32)),
+ )
+ block_1_bad = recursive_replace(
+ blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
+ )
+
+ result, err, _ = await blockchain.receive_block(block_1_bad)
+ assert result == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.INVALID_CHALLENGE_SLOT_HASH_RC
+
+ @pytest.mark.asyncio
+ async def test_invalid_cc_sub_slot_vdf(self, empty_blockchain):
+ # 2q
+ blocks = bt.get_consecutive_blocks(10)
+ for block in blocks:
+ if len(block.finished_sub_slots):
+ # Bad iters
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[-1],
+ "challenge_chain",
+ recursive_replace(
+ block.finished_sub_slots[-1].challenge_chain,
+ "challenge_chain_end_of_slot_vdf.number_of_iterations",
+ uint64(10000000),
+ ),
+ )
+ new_finished_ss = recursive_replace(
+ new_finished_ss,
+ "reward_chain.challenge_chain_sub_slot_hash",
+ new_finished_ss.challenge_chain.get_hash(),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_CC_EOS_VDF
+
+ # Bad output
+ new_finished_ss_2 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "challenge_chain",
+ recursive_replace(
+ block.finished_sub_slots[-1].challenge_chain,
+ "challenge_chain_end_of_slot_vdf.output",
+ ClassgroupElement.get_default_element(),
+ ),
+ )
+
+ new_finished_ss_2 = recursive_replace(
+ new_finished_ss_2,
+ "reward_chain.challenge_chain_sub_slot_hash",
+ new_finished_ss_2.challenge_chain.get_hash(),
+ )
+ block_bad_2 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_2)
+ assert err == Err.INVALID_CC_EOS_VDF
+
+ # Bad challenge hash
+ new_finished_ss_3 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "challenge_chain",
+ recursive_replace(
+ block.finished_sub_slots[-1].challenge_chain,
+ "challenge_chain_end_of_slot_vdf.challenge",
+ bytes([1] * 32),
+ ),
+ )
+
+ new_finished_ss_3 = recursive_replace(
+ new_finished_ss_3,
+ "reward_chain.challenge_chain_sub_slot_hash",
+ new_finished_ss_3.challenge_chain.get_hash(),
+ )
+ block_bad_3 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_3)
+ assert err == Err.INVALID_CC_EOS_VDF or err == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
+
+ # Bad proof
+ new_finished_ss_5 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "proofs.challenge_chain_slot_proof",
+ VDFProof(uint8(0), b"1239819023890"),
+ )
+ block_bad_5 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_5)
+ assert err == Err.INVALID_CC_EOS_VDF
+
+ result, err, _ = await empty_blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_invalid_rc_sub_slot_vdf(self, empty_blockchain):
+ # 2p
+ blocks = bt.get_consecutive_blocks(10)
+ for block in blocks:
+ if len(block.finished_sub_slots):
+ # Bad iters
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[-1],
+ "reward_chain",
+ recursive_replace(
+ block.finished_sub_slots[-1].reward_chain,
+ "end_of_slot_vdf.number_of_iterations",
+ uint64(10000000),
+ ),
+ )
+ block_bad = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_RC_EOS_VDF
+
+ # Bad output
+ new_finished_ss_2 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "reward_chain",
+ recursive_replace(
+ block.finished_sub_slots[-1].reward_chain,
+ "end_of_slot_vdf.output",
+ ClassgroupElement.get_default_element(),
+ ),
+ )
+ block_bad_2 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_2)
+ assert err == Err.INVALID_RC_EOS_VDF
+
+ # Bad challenge hash
+ new_finished_ss_3 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "reward_chain",
+ recursive_replace(
+ block.finished_sub_slots[-1].reward_chain,
+ "end_of_slot_vdf.challenge",
+ bytes([1] * 32),
+ ),
+ )
+ block_bad_3 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_3)
+ assert err == Err.INVALID_RC_EOS_VDF
+
+ # Bad proof
+ new_finished_ss_5 = recursive_replace(
+ block.finished_sub_slots[-1],
+ "proofs.reward_chain_slot_proof",
+ VDFProof(uint8(0), b"1239819023890"),
+ )
+ block_bad_5 = recursive_replace(
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad_5)
+ assert err == Err.INVALID_RC_EOS_VDF
+
+ result, err, _ = await empty_blockchain.receive_block(block)
+ assert err is None
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_genesis_bad_deficit(self, empty_blockchain):
+ # 2r
+ block = bt.get_consecutive_blocks(1, skip_slots=2)[0]
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[-1],
+ "reward_chain",
+ recursive_replace(
+ block.finished_sub_slots[-1].reward_chain,
+ "deficit",
+ test_constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK - 1,
+ ),
+ )
+ block_bad = recursive_replace(block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss])
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_DEFICIT
+
+ @pytest.mark.asyncio
+ async def test_reset_deficit(self, empty_blockchain):
+ # 2s, 2t
+ blockchain = empty_blockchain
+ blocks = bt.get_consecutive_blocks(2)
+ await empty_blockchain.receive_block(blocks[0])
+ await empty_blockchain.receive_block(blocks[1])
+ case_1, case_2 = False, False
+ while not case_1 or not case_2:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
+ if len(blocks[-1].finished_sub_slots) > 0:
+ new_finished_ss = recursive_replace(
+ blocks[-1].finished_sub_slots[-1],
+ "reward_chain",
+ recursive_replace(
+ blocks[-1].finished_sub_slots[-1].reward_chain,
+ "deficit",
+ uint8(0),
+ ),
+ )
+ if blockchain.sub_blocks[blocks[-2].header_hash].deficit == 0:
+ case_1 = True
+ else:
+ case_2 = True
+
+ block_bad = recursive_replace(
+ blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_DEFICIT or err == Err.INVALID_ICC_HASH_CC
+
+ result, err, _ = await empty_blockchain.receive_block(blocks[-1])
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_genesis_has_ses(self, empty_blockchain):
+ # 3a
+ block = bt.get_consecutive_blocks(1, skip_slots=1)[0]
+ new_finished_ss = recursive_replace(
+ block.finished_sub_slots[0],
+ "challenge_chain",
+ recursive_replace(
+ block.finished_sub_slots[0].challenge_chain,
+ "subepoch_summary_hash",
+ bytes([0] * 32),
+ ),
+ )
+
+ new_finished_ss = recursive_replace(
+ new_finished_ss,
+ "reward_chain",
+ replace(
+ new_finished_ss.reward_chain, challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash()
+ ),
+ )
+ block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:])
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
+
+ @pytest.mark.asyncio
+ async def test_no_ses_if_no_se(self, empty_blockchain):
+ # 3b
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if len(blocks[-1].finished_sub_slots) > 0:
+ new_finished_ss: EndOfSubSlotBundle = recursive_replace(
+ blocks[-1].finished_sub_slots[0],
+ "challenge_chain",
+ recursive_replace(
+ blocks[-1].finished_sub_slots[0].challenge_chain,
+ "subepoch_summary_hash",
+ bytes([0] * 32),
+ ),
+ )
+
+ new_finished_ss = recursive_replace(
+ new_finished_ss,
+ "reward_chain",
+ replace(
+ new_finished_ss.reward_chain,
+ challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash(),
+ ),
+ )
+ block_bad = recursive_replace(
+ blocks[-1], "finished_sub_slots", [new_finished_ss] + blocks[-1].finished_sub_slots[1:]
+ )
+ result, err, _ = await empty_blockchain.receive_block(block_bad)
+ assert err == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
+ return
+ await empty_blockchain.receive_block(blocks[-1])
+
+ @pytest.mark.asyncio
+ async def test_too_many_sub_blocks(self, empty_blockchain):
+ # 4: TODO
+ pass
+
+ @pytest.mark.asyncio
+ async def test_bad_pos(self, empty_blockchain):
+ # 5
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.proof_of_space.challenge", std_hash(b""))
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
+
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.proof_of_space.pool_contract_puzzle_hash", std_hash(b"")
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
+
+ block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.proof_of_space.pool_public_key", None)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
+
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.proof_of_space.plot_public_key",
+ AugSchemeMPL.key_gen(std_hash(b"1231n")).get_g1(),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.proof_of_space.size",
+ 32,
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.proof_of_space.proof",
+ bytes([1] * int(blocks[-1].reward_chain_sub_block.proof_of_space.size * 64 / 8)),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POSPACE
+
+ # TODO: test not passing the plot filter
+
+ @pytest.mark.asyncio
+ async def test_bad_signage_point_index(self, empty_blockchain):
+ # 6
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ with pytest.raises(ValueError):
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.signage_point_index", test_constants.NUM_SPS_SUB_SLOT
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_SP_INDEX
+ with pytest.raises(ValueError):
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.signage_point_index", test_constants.NUM_SPS_SUB_SLOT + 1
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_SP_INDEX
+
+ @pytest.mark.asyncio
+ async def test_sp_0_no_sp(self, empty_blockchain):
+ # 7
+ blocks = []
+ case_1, case_2 = False, False
+ while not case_1 or not case_2:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].reward_chain_sub_block.signage_point_index == 0:
+ case_1 = True
+ block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.signage_point_index", uint8(1))
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_SP_INDEX
+ else:
+ case_2 = True
+ block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.signage_point_index", uint8(0))
+ error_code = (await empty_blockchain.receive_block(block_bad))[1]
+ assert error_code == Err.INVALID_SP_INDEX or error_code == Err.INVALID_POSPACE
+ assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_epoch_overflows(self, empty_blockchain):
+ # 9. TODO. This is hard to test because it requires modifying the block tools to make these special blocks
+ pass
+
+ @pytest.mark.asyncio
+ async def test_bad_total_iters(self, empty_blockchain):
+ # 10
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.total_iters", blocks[-1].reward_chain_sub_block.total_iters + 1
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_TOTAL_ITERS
+
+ @pytest.mark.asyncio
+ async def test_bad_rc_sp_vdf(self, empty_blockchain):
+ # 11
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].reward_chain_sub_block.signage_point_index != 0:
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.reward_chain_sp_vdf.challenge", std_hash(b"1")
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.reward_chain_sp_vdf.output",
+ ClassgroupElement(int512(10), int512(2)),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.reward_chain_sp_vdf.number_of_iterations",
+ uint64(1111111111111),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sp_proof",
+ VDFProof(uint8(0), std_hash(b"")),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SP_VDF
+ return
+ assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_bad_rc_sp_sig(self, empty_blockchain):
+ # 12
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.reward_chain_sp_signature", G2Element.generator()
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_SIGNATURE
+
+ @pytest.mark.asyncio
+ async def test_bad_cc_sp_vdf(self, empty_blockchain):
+ # 13. Note: does not validate fully due to proof of space being validated first
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].reward_chain_sub_block.signage_point_index != 0:
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.challenge_chain_sp_vdf.challenge", std_hash(b"1")
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[0] == ReceiveBlockResult.INVALID_BLOCK
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.challenge_chain_sp_vdf.output",
+ ClassgroupElement(int512(10), int512(2)),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[0] == ReceiveBlockResult.INVALID_BLOCK
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.challenge_chain_sp_vdf.number_of_iterations",
+ uint64(1111111111111),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[0] == ReceiveBlockResult.INVALID_BLOCK
+ block_bad = recursive_replace(
+ blocks[-1],
+ "challenge_chain_sp_proof",
+ VDFProof(uint8(0), std_hash(b"")),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_SP_VDF
+ return
+ assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_bad_cc_sp_sig(self, empty_blockchain):
+ # 14
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.challenge_chain_sp_signature", G2Element.generator()
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_SIGNATURE
+
+ @pytest.mark.asyncio
+ async def test_is_block(self, empty_blockchain):
+ # 15: TODO
+ pass
+
+ @pytest.mark.asyncio
+ async def test_bad_foliage_sb_sig(self, empty_blockchain):
+ # 16
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_sub_block_signature", G2Element.generator()
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PLOT_SIGNATURE
+
+ @pytest.mark.asyncio
+ async def test_bad_foliage_block_sig(self, empty_blockchain):
+ # 17
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].foliage_block is not None:
+ block_bad = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_block_signature", G2Element.generator()
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PLOT_SIGNATURE
+ return
+ assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ @pytest.mark.asyncio
+ async def test_unfinished_reward_chain_sb_hash(self, empty_blockchain):
+ # 18
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_sub_block_data.unfinished_reward_block_hash", std_hash(b"2")
+ )
+ new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_URSB_HASH
+
+ @pytest.mark.asyncio
+ async def test_pool_target_height(self, empty_blockchain):
+ # 19
+ blocks = bt.get_consecutive_blocks(3)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ assert (await empty_blockchain.receive_block(blocks[1]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_sub_block_data.pool_target.max_height", 1
+ )
+ new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.OLD_POOL_TARGET
+
+ @pytest.mark.asyncio
+ async def test_pool_target_pre_farm(self, empty_blockchain):
+ # 20a
+ blocks = bt.get_consecutive_blocks(1)
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_sub_block_data.pool_target.puzzle_hash", std_hash(b"12")
+ )
+ new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREFARM
+
+ @pytest.mark.asyncio
+ async def test_pool_target_signature(self, empty_blockchain):
+ # 20b
+ blocks = bt.get_consecutive_blocks(3)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ assert (await empty_blockchain.receive_block(blocks[1]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_sub_block_data.pool_signature", G2Element.generator()
+ )
+ new_m = block_bad.foliage_sub_block.foliage_sub_block_data.get_hash()
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_sub_block_signature", new_fsb_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_POOL_SIGNATURE
+
+ @pytest.mark.asyncio
+ async def test_foliage_data_presence(self, empty_blockchain):
+ # 22
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ case_1, case_2 = False, False
+ while not case_1 or not case_2:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].foliage_block is not None:
+ case_1 = True
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_sub_block.foliage_block_hash", None)
+ else:
+ case_2 = True
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_block_hash", std_hash(b"")
+ )
+ err_code = (await empty_blockchain.receive_block(block_bad))[1]
+ assert err_code == Err.INVALID_FOLIAGE_BLOCK_PRESENCE or err_code == Err.INVALID_IS_BLOCK
+ await empty_blockchain.receive_block(blocks[-1])
+
+ @pytest.mark.asyncio
+ async def test_foliage_block_hash(self, empty_blockchain):
+ # 23
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ case_1, case_2 = False, False
+ while not case_1 or not case_2:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].foliage_block is not None:
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_sub_block.foliage_block_hash", std_hash(b"2")
+ )
+
+ new_m = block_bad.foliage_sub_block.foliage_block_hash
+ new_fbh_sig = bt.get_plot_signature(
+ new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
+ )
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_FOLIAGE_BLOCK_HASH
+ return
+ await empty_blockchain.receive_block(blocks[-1])
+
+ @pytest.mark.asyncio
+ async def test_genesis_bad_prev_block(self, empty_blockchain):
+ # 24a
+ blocks = bt.get_consecutive_blocks(1)
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.prev_block_hash", std_hash(b"2"))
+ block_bad: FullBlock = recursive_replace(
+ block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
+ )
+ new_m = block_bad.foliage_sub_block.foliage_block_hash
+ new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key)
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREV_BLOCK_HASH
+
+ @pytest.mark.asyncio
+ async def test_bad_prev_block_non_genesis(self, empty_blockchain):
+ # 24b
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].foliage_block is not None:
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.prev_block_hash", std_hash(b"2"))
+ block_bad: FullBlock = recursive_replace(
+ block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
+ )
+ new_m = block_bad.foliage_sub_block.foliage_block_hash
+ new_fbh_sig = bt.get_plot_signature(
+ new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
+ )
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREV_BLOCK_HASH
+ return
+ await empty_blockchain.receive_block(blocks[-1])
+
+ @pytest.mark.asyncio
+ async def test_bad_filter_hash(self, empty_blockchain):
+ # 25
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].foliage_block is not None:
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.filter_hash", std_hash(b"2"))
+ block_bad: FullBlock = recursive_replace(
+ block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
+ )
+ new_m = block_bad.foliage_sub_block.foliage_block_hash
+ new_fbh_sig = bt.get_plot_signature(
+ new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
+ )
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_TRANSACTIONS_FILTER_HASH
+ return
+ await empty_blockchain.receive_block(blocks[-1])
+
+ @pytest.mark.asyncio
+ async def test_bad_timestamp(self, empty_blockchain):
+ # 26
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if blocks[-1].foliage_block is not None:
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_block.timestamp", blocks[0].foliage_block.timestamp - 10
+ )
+ block_bad: FullBlock = recursive_replace(
+ block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
+ )
+ new_m = block_bad.foliage_sub_block.foliage_block_hash
+ new_fbh_sig = bt.get_plot_signature(
+ new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
+ )
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.TIMESTAMP_TOO_FAR_IN_PAST
+
+ block_bad: FullBlock = recursive_replace(
+ blocks[-1], "foliage_block.timestamp", blocks[0].foliage_block.timestamp + 10000000
+ )
+ block_bad: FullBlock = recursive_replace(
+ block_bad, "foliage_sub_block.foliage_block_hash", block_bad.foliage_block.get_hash()
+ )
+ new_m = block_bad.foliage_sub_block.foliage_block_hash
+ new_fbh_sig = bt.get_plot_signature(
+ new_m, blocks[-1].reward_chain_sub_block.proof_of_space.plot_public_key
+ )
+ block_bad = recursive_replace(block_bad, "foliage_sub_block.foliage_block_signature", new_fbh_sig)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.TIMESTAMP_TOO_FAR_IN_FUTURE
+ return
+ await empty_blockchain.receive_block(blocks[-1])
+
+ @pytest.mark.asyncio
+ async def test_sub_block_height(self, empty_blockchain):
+ # 27
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.sub_block_height", 2)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_HEIGHT
+
+ @pytest.mark.asyncio
+ async def test_sub_block_height_genesis(self, empty_blockchain):
+ # 27
+ blocks = bt.get_consecutive_blocks(1)
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.sub_block_height", 1)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_PREV_BLOCK_HASH
+
+ @pytest.mark.asyncio
+ async def test_weight(self, empty_blockchain):
+ # 28
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.weight", 22131)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_WEIGHT
+
+ @pytest.mark.asyncio
+ async def test_weight_genesis(self, empty_blockchain):
+ # 28
+ blocks = bt.get_consecutive_blocks(1)
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.weight", 0)
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_WEIGHT
+
+ @pytest.mark.asyncio
+ async def test_bad_cc_ip_vdf(self, empty_blockchain):
+ # 29
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.challenge_chain_ip_vdf.challenge", std_hash(b"1")
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.challenge_chain_ip_vdf.output",
+ ClassgroupElement(int512(10), int512(2)),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.challenge_chain_ip_vdf.number_of_iterations",
+ uint64(1111111111111),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "challenge_chain_ip_proof",
+ VDFProof(uint8(0), std_hash(b"")),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_CC_IP_VDF
+
+ @pytest.mark.asyncio
+ async def test_bad_rc_ip_vdf(self, empty_blockchain):
+ # 30
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.reward_chain_ip_vdf.challenge", std_hash(b"1")
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.reward_chain_ip_vdf.output",
+ ClassgroupElement(int512(10), int512(2)),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.reward_chain_ip_vdf.number_of_iterations",
+ uint64(1111111111111),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_ip_proof",
+ VDFProof(uint8(0), std_hash(b"")),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_RC_IP_VDF
+
+ @pytest.mark.asyncio
+ async def test_bad_icc_ip_vdf(self, empty_blockchain):
+ # 31
+ blocks = bt.get_consecutive_blocks(1)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ block_bad = recursive_replace(
+ blocks[-1], "reward_chain_sub_block.infused_challenge_chain_ip_vdf.challenge", std_hash(b"1")
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.infused_challenge_chain_ip_vdf.output",
+ ClassgroupElement(int512(10), int512(2)),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "reward_chain_sub_block.infused_challenge_chain_ip_vdf.number_of_iterations",
+ uint64(1111111111111),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
+ block_bad = recursive_replace(
+ blocks[-1],
+ "infused_challenge_chain_ip_proof",
+ VDFProof(uint8(0), std_hash(b"")),
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_ICC_VDF
+
+ @pytest.mark.asyncio
+ async def test_reward_block_hash(self, empty_blockchain):
+ # 32
+ blocks = bt.get_consecutive_blocks(2)
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_sub_block.reward_block_hash", std_hash(b""))
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_REWARD_BLOCK_HASH
+
+ @pytest.mark.asyncio
+ async def test_reward_block_hash_2(self, empty_blockchain):
+ # 33
+ blocks = bt.get_consecutive_blocks(1)
+ block_bad: FullBlock = recursive_replace(blocks[0], "reward_chain_sub_block.is_block", False)
+ block_bad: FullBlock = recursive_replace(
+ block_bad, "foliage_sub_block.reward_block_hash", block_bad.reward_chain_sub_block.get_hash()
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_FOLIAGE_BLOCK_PRESENCE
+ assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
+
+ # Test one which should not be a block
+ while True:
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
+ if not blocks[-1].is_block():
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.is_block", True)
+ block_bad: FullBlock = recursive_replace(
+ block_bad, "foliage_sub_block.reward_block_hash", block_bad.reward_chain_sub_block.get_hash()
+ )
+ assert (await empty_blockchain.receive_block(block_bad))[1] == Err.INVALID_FOLIAGE_BLOCK_PRESENCE
+ return
+ assert (await empty_blockchain.receive_block(blocks[-1]))[0] == ReceiveBlockResult.NEW_PEAK
+
+
+class TestBodyValidation:
+ @pytest.mark.asyncio
+ async def test_not_block_but_has_data(self, empty_blockchain):
+ # TODO
+ pass
+
+
+class TestReorgs:
+ @pytest.mark.asyncio
+ async def test_basic_reorg(self, empty_blockchain):
+ b = empty_blockchain
+ blocks = bt.get_consecutive_blocks(15)
+
+ for block in blocks:
+ assert (await b.receive_block(block))[0] == ReceiveBlockResult.NEW_PEAK
+ assert b.get_peak().sub_block_height == 14
+
+ blocks_reorg_chain = bt.get_consecutive_blocks(7, blocks[:10], seed=b"2")
+ for reorg_block in blocks_reorg_chain:
+ result, error_code, fork_height = await b.receive_block(reorg_block)
+ if reorg_block.sub_block_height < 10:
+ assert result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
+ elif reorg_block.sub_block_height < 14:
+ assert result == ReceiveBlockResult.ADDED_AS_ORPHAN
+ elif reorg_block.sub_block_height >= 15:
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert error_code is None
+ assert b.get_peak().sub_block_height == 16
+
+ @pytest.mark.asyncio
+ async def test_long_reorg(self, empty_blockchain):
+ # Reorg longer than a difficulty adjustment
+ # Also tests higher weight chain but lower height
+ b = empty_blockchain
+ num_blocks_chain_1 = 3 * test_constants.EPOCH_SUB_BLOCKS + test_constants.MAX_SUB_SLOT_SUB_BLOCKS + 10
+ num_blocks_chain_2_start = test_constants.EPOCH_SUB_BLOCKS - 20
+ num_blocks_chain_2 = 3 * test_constants.EPOCH_SUB_BLOCKS + test_constants.MAX_SUB_SLOT_SUB_BLOCKS + 8
+
+ blocks = bt.get_consecutive_blocks(num_blocks_chain_1)
+
+ for block in blocks:
+ assert (await b.receive_block(block))[0] == ReceiveBlockResult.NEW_PEAK
+ chain_1_height = b.get_peak().sub_block_height
+ chain_1_weight = b.get_peak().weight
+ assert chain_1_height == (num_blocks_chain_1 - 1)
+
+ # These blocks will have less time between them (timestamp) and therefore will make difficulty go up
+ # This means that the weight will grow faster, and we can get a heavier chain with lower height
+ blocks_reorg_chain = bt.get_consecutive_blocks(
+ num_blocks_chain_2 - num_blocks_chain_2_start,
+ blocks[:num_blocks_chain_2_start],
+ seed=b"2",
+ time_per_sub_block=8,
+ )
+ found_orphan = False
+ for reorg_block in blocks_reorg_chain:
+ result, error_code, fork_height = await b.receive_block(reorg_block)
+ if reorg_block.sub_block_height < num_blocks_chain_2_start:
+ assert result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
+ if reorg_block.weight <= chain_1_weight:
+ if result == ReceiveBlockResult.ADDED_AS_ORPHAN:
+ found_orphan = True
+ assert error_code is None
+ assert result == ReceiveBlockResult.ADDED_AS_ORPHAN or result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
+ elif reorg_block.weight > chain_1_weight:
+ assert reorg_block.sub_block_height < chain_1_height
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert error_code is None
+ assert found_orphan
+
+ assert b.get_peak().weight > chain_1_weight
+ assert b.get_peak().sub_block_height < chain_1_height
+
+ @pytest.mark.asyncio
+ async def test_reorg_from_genesis(self, empty_blockchain):
+ b = empty_blockchain
+ blocks = bt.get_consecutive_blocks(15)
+
+ for block in blocks:
+ assert (await b.receive_block(block))[0] == ReceiveBlockResult.NEW_PEAK
+ assert b.get_peak().sub_block_height == 14
+
+ # Reorg to alternate chain that is 1 height longer
+ found_orphan = False
+ blocks_reorg_chain = bt.get_consecutive_blocks(16, [], seed=b"2")
+ for reorg_block in blocks_reorg_chain:
+ result, error_code, fork_height = await b.receive_block(reorg_block)
+ if reorg_block.sub_block_height < 14:
+ if result == ReceiveBlockResult.ADDED_AS_ORPHAN:
+ found_orphan = True
+ assert result == ReceiveBlockResult.ADDED_AS_ORPHAN or result == ReceiveBlockResult.ALREADY_HAVE_BLOCK
+ elif reorg_block.sub_block_height >= 15:
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert error_code is None
+
+ # Back to original chain
+ blocks_reorg_chain_2 = bt.get_consecutive_blocks(3, blocks, seed=b"3")
+
+ result, error_code, fork_height = await b.receive_block(blocks_reorg_chain_2[-3])
+ assert result == ReceiveBlockResult.ADDED_AS_ORPHAN
+
+ result, error_code, fork_height = await b.receive_block(blocks_reorg_chain_2[-2])
+ assert result == ReceiveBlockResult.NEW_PEAK
+
+ result, error_code, fork_height = await b.receive_block(blocks_reorg_chain_2[-1])
+ assert result == ReceiveBlockResult.NEW_PEAK
+ assert found_orphan
+ assert b.get_peak().sub_block_height == 17
diff --git a/tests/consensus/test_pot_iterations.py b/tests/consensus/test_pot_iterations.py
index f083cf3746..33c721a3ac 100644
--- a/tests/consensus/test_pot_iterations.py
+++ b/tests/consensus/test_pot_iterations.py
@@ -10,12 +10,7 @@ from src.util.ints import uint8, uint64
from src.consensus.default_constants import DEFAULT_CONSTANTS
from pytest import raises
-test_constants = DEFAULT_CONSTANTS.replace(
- **{
- "NUM_SPS_SUB_SLOT": 32,
- "SUB_SLOT_TIME_TARGET": 300,
- }
-)
+test_constants = DEFAULT_CONSTANTS.replace(**{"NUM_SPS_SUB_SLOT": 32, "SUB_SLOT_TIME_TARGET": 300})
class TestPotIterations:
@@ -58,7 +53,6 @@ class TestPotIterations:
required_iters = sp_interval_iters - 1
ip_iters = calculate_ip_iters(test_constants, ssi, uint8(13), required_iters)
- print(sp_iters, sp_interval_iters, required_iters)
assert ip_iters == sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters
required_iters = uint64(1)
@@ -115,8 +109,6 @@ class TestPotIterations:
total_wins_in_slot += 1
win_percentage = {k: wins[k] / sum(wins.values()) for k in farmer_ks.keys()}
- print(win_percentage)
- print(percentage_space)
for k in farmer_ks.keys():
# Win rate is proportional to percentage of space
assert abs(win_percentage[k] - percentage_space[k]) < 0.01
diff --git a/tests/full_node/test_blockchain_transactions.py b/tests/full_node/test_blockchain_transactions.py
index d88ef1160c..7970bca4d7 100644
--- a/tests/full_node/test_blockchain_transactions.py
+++ b/tests/full_node/test_blockchain_transactions.py
@@ -3,8 +3,10 @@ import pytest
from src.consensus.blockchain import ReceiveBlockResult
from src.protocols import full_node_protocol
+from src.types.condition_opcodes import ConditionOpcode
+from src.types.condition_var_pair import ConditionVarPair
from src.types.spend_bundle import SpendBundle
-from src.util.errors import Err
+from src.util.errors import Err, ConsensusError
from tests.full_node.test_full_node import connect_and_get_peer
from tests.setup_nodes import setup_two_nodes, test_constants, bt
from src.util.wallet_tools import WalletTool
@@ -75,7 +77,6 @@ class TestBlockchainTransactions:
await full_node_1.respond_sub_block(full_node_protocol.RespondSubBlock(next_block))
assert next_block.header_hash == full_node_1.blockchain.get_peak().header_hash
- print("Adde block ", next_block)
added_coins = next_spendbundle.additions()
@@ -127,458 +128,408 @@ class TestBlockchainTransactions:
assert res == ReceiveBlockResult.INVALID_BLOCK
assert err == Err.DOUBLE_SPEND
+ @pytest.mark.asyncio
+ async def test_validate_blockchain_duplicate_output(self, two_nodes):
+ num_blocks = 3
+ wallet_a = WALLET_A
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
+ receiver_puzzlehash = BURN_PUZZLE_HASH
-# @pytest.mark.asyncio
-# async def test_validate_blockchain_duplicate_output(self, two_nodes):
-# num_blocks = 10
-# wallet_a = WALLET_A
-# coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
-# receiver_puzzlehash = BURN_PUZZLE_HASH
-#
-# blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash)
-# full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
-# full_node_1 = full_node_api_1.full_node
-#
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# spent_block = blocks[1]
-#
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spent_block.get_coinbase())
-# spend_bundle_double = wallet_a.generate_signed_transaction(
-# 1000, receiver_puzzlehash, spent_block.get_coinbase()
-# )
-#
-# block_spendbundle = SpendBundle.aggregate([spend_bundle, spend_bundle_double])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {(num_blocks + 1): (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h)
-#
-# next_block = new_blocks[(num_blocks + 1)]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-#
-# assert error is Err.DUPLICATE_OUTPUT
-#
-# @pytest.mark.asyncio
-# async def test_validate_blockchain_with_reorg_double_spend(self, two_nodes):
-# num_blocks = 10
-# wallet_a = WALLET_A
-# coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
-# receiver_puzzlehash = BURN_PUZZLE_HASH
-#
-# blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash)
-# full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
-# full_node_1 = full_node_api_1.full_node
-#
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# spent_block = blocks[1]
-#
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spent_block.get_coinbase())
-# block_spendbundle = SpendBundle.aggregate([spend_bundle])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {11: (program, aggsig)}
-# blocks = bt.get_consecutive_blocks(test_constants, 10, blocks, 10, b"", coinbase_puzzlehash, dic_h)
-# # Move chain to height 20, with a spend at height 11
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# # Reorg at block 5, same spend at block 13 and 14 that was previously at block 11
-# dic_h = {13: (program, aggsig), 14: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 9,
-# blocks[:6],
-# 10,
-# b"another seed",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-#
-# for block in new_blocks[:13]:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-# next_block = new_blocks[13]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-# assert error is None
-#
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[13]))
-#
-# next_block = new_blocks[14]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-# assert error is Err.DOUBLE_SPEND
-#
-# # Now test Reorg at block 5, same spend at block 9 that was previously at block 11
-# dic_h = {9: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 4,
-# blocks[:6],
-# 10,
-# b"another seed 2",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# for block in new_blocks[:9]:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-# next_block = new_blocks[9]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-# assert error is None
-#
-# # Now test Reorg at block 10, same spend at block 11 that was previously at block 11
-# dic_h = {11: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 4,
-# blocks[:11],
-# 10,
-# b"another seed 3",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# for block in new_blocks[:11]:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-# next_block = new_blocks[11]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-# assert error is None
-#
-# # Now test Reorg at block 11, same spend at block 12 that was previously at block 11
-# dic_h = {12: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 4,
-# blocks[:12],
-# 10,
-# b"another seed 4",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# for block in new_blocks[:12]:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-# next_block = new_blocks[12]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-# assert error is Err.DOUBLE_SPEND
-#
-# # Now test Reorg at block 11, same spend at block 15 that was previously at block 11
-# dic_h = {15: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 4,
-# blocks[:12],
-# 10,
-# b"another seed 5",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# for block in new_blocks[:15]:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-# next_block = new_blocks[15]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-# assert error is Err.DOUBLE_SPEND
-#
-# @pytest.mark.asyncio
-# async def test_validate_blockchain_spend_reorg_coin(self, two_nodes):
-# num_blocks = 10
-# wallet_a = WALLET_A
-# coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
-# receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
-# receiver_2_puzzlehash = WALLET_A_PUZZLE_HASHES[2]
-# receiver_3_puzzlehash = WALLET_A_PUZZLE_HASHES[3]
-#
-# blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash)
-# full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
-# full_node_1 = full_node_api_1.full_node
-#
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# spent_block = blocks[1]
-#
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash, spent_block.get_coinbase())
-# block_spendbundle = SpendBundle.aggregate([spend_bundle])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {5: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 1,
-# blocks[:5],
-# 10,
-# b"spend_reorg_coin",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-#
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
-# assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
-#
-# coin_2 = None
-# for coin in new_blocks[-1].additions():
-# if coin.puzzle_hash == receiver_1_puzzlehash:
-# coin_2 = coin
-# break
-# assert coin_2 is not None
-#
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_2_puzzlehash, coin_2)
-# block_spendbundle = SpendBundle.aggregate([spend_bundle])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {6: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 1,
-# new_blocks[:6],
-# 10,
-# b"spend_reorg_coin",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
-# assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
-#
-# coin_3 = None
-# for coin in new_blocks[-1].additions():
-# if coin.puzzle_hash == receiver_2_puzzlehash:
-# coin_3 = coin
-# break
-# assert coin_3 is not None
-#
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_3_puzzlehash, coin_3)
-# block_spendbundle = SpendBundle.aggregate([spend_bundle])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {7: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 1,
-# new_blocks[:7],
-# 10,
-# b"spend_reorg_coin",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-#
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
-# assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
-#
-# coin_4 = None
-# for coin in new_blocks[-1].additions():
-# if coin.puzzle_hash == receiver_3_puzzlehash:
-# coin_4 = coin
-# break
-# assert coin_4 is not None
-#
-# @pytest.mark.asyncio
-# async def test_validate_blockchain_spend_reorg_cb_coin(self, two_nodes):
-# num_blocks = 10
-# wallet_a = WALLET_A
-# coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
-# receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
-#
-# blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash)
-# full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
-# full_node_1 = full_node_api_1.full_node
-#
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# # Spends a coinbase created in reorg
-# new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks[:6],
-# 10, b"reorg cb coin", coinbase_puzzlehash)
-#
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
-# assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
-#
-# spent_block = new_blocks[-1]
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash,
-# spent_block.get_coinbase())
-# spend_bundle_2 = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash,
-# spent_block.get_fees_coin())
-#
-# block_spendbundle = SpendBundle.aggregate([spend_bundle, spend_bundle_2])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {7: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 1,
-# new_blocks,
-# 10,
-# b"reorg cb coin",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# error = await full_node_1.blockchain._validate_transactions(
-# new_blocks[-1], new_blocks[-1].get_fees_coin().amount
-# )
-# assert error is None
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
-# assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
-#
-# coins_created = []
-# for coin in new_blocks[-1].additions():
-# if coin.puzzle_hash == receiver_1_puzzlehash:
-# coins_created.append(coin)
-# assert len(coins_created) == 2
-#
-# @pytest.mark.asyncio
-# async def test_validate_blockchain_spend_reorg_cb_coin_freeze(self, two_nodes_standard_freeze):
-# num_blocks = 10
-# wallet_a = WALLET_A
-# coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
-# receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
-#
-# blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash)
-# full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes_standard_freeze
-# full_node_1 = full_node_api_1.full_node
-#
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# # Spends a coinbase created in reorg
-# new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks[:6], 10,
-# b"reorg cb coin", coinbase_puzzlehash)
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
-#
-# assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
-#
-# spent_block = new_blocks[-1]
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash, spent_block.get_coinbase())
-# block_spendbundle = SpendBundle.aggregate([spend_bundle])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {7: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 1,
-# new_blocks,
-# 10,
-# b"reorg cb coin",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# error = await full_node_1.blockchain._validate_transactions(
-# new_blocks[-1], new_blocks[-1].get_coinbase().amount
-# )
-# assert error is Err.COINBASE_NOT_YET_SPENDABLE
-#
-# @pytest.mark.asyncio
-# async def test_validate_blockchain_spend_reorg_since_genesis(self, two_nodes):
-# num_blocks = 10
-# wallet_a = WALLET_A
-# coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
-# receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
-#
-# blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash)
-# full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
-# full_node_1 = full_node_api_1.full_node
-#
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# spent_block = blocks[1]
-#
-# spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash, spent_block.get_coinbase())
-# block_spendbundle = SpendBundle.aggregate([spend_bundle])
-# program = best_solution_program(block_spendbundle)
-# aggsig = block_spendbundle.aggregated_signature
-#
-# dic_h = {11: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h)
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
-#
-# # Spends a coin in a genesis reorg, that was already spent
-# dic_h = {5: (program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(
-# test_constants,
-# 12,
-# [],
-# 10,
-# b"reorg since genesis",
-# coinbase_puzzlehash,
-# dic_h,
-# )
-# for block in new_blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
-#
-# @pytest.mark.asyncio
-# async def test_assert_my_coin_id(self, two_nodes):
-# num_blocks = 10
-# wallet_a = WALLET_A
-# coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
-# receiver_puzzlehash = BURN_PUZZLE_HASH
-#
-# # Farm blocks
-# blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash)
-# full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
-# full_node_1 = full_node_api_1.full_node
-#
-# for block in blocks:
-# await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
-#
-# # Coinbase that gets spent
-# spent_block = blocks[1]
-# bad_block = blocks[2]
-# valid_cvp = ConditionVarPair(
-# ConditionOpcode.ASSERT_MY_COIN_ID,
-# spent_block.get_coinbase().name(),
-# None,
-# )
-# valid_dic = {valid_cvp.opcode: [valid_cvp]}
-# bad_cvp = ConditionVarPair(
-# ConditionOpcode.ASSERT_MY_COIN_ID,
-# bad_block.get_coinbase().name(),
-# None,
-# )
-#
-# bad_dic = {bad_cvp.opcode: [bad_cvp]}
-# bad_spend_bundle = wallet_a.generate_signed_transaction(
-# 1000, receiver_puzzlehash, spent_block.get_coinbase(), bad_dic
-# )
-#
-# valid_spend_bundle = wallet_a.generate_signed_transaction(
-# 1000, receiver_puzzlehash, spent_block.get_coinbase(), valid_dic
-# )
-#
-# # Invalid block bundle
-# assert bad_spend_bundle is not None
-# invalid_program = best_solution_program(bad_spend_bundle)
-# aggsig = bad_spend_bundle.aggregated_signature
-#
-# # Create another block that includes our transaction
-# dic_h = {11: (invalid_program, aggsig)}
-# invalid_new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h)
-#
-# # Try to validate that block
-# next_block = invalid_new_blocks[11]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-#
-# assert error is Err.ASSERT_MY_COIN_ID_FAILED
-#
-# # Valid block bundle
-# assert valid_spend_bundle is not None
-# valid_program = best_solution_program(valid_spend_bundle)
-# aggsig = valid_spend_bundle.aggregated_signature
-#
-# # Create another block that includes our transaction
-# dic_h = {11: (valid_program, aggsig)}
-# new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks[:11], 10, b"1", coinbase_puzzlehash, dic_h)
-# next_block = new_blocks[11]
-# error = await full_node_1.blockchain._validate_transactions(next_block, next_block.get_fees_coin().amount)
-# assert error is None
-#
-# @pytest.mark.asyncio
+ blocks = bt.get_consecutive_blocks(
+ num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_block=True
+ )
+ full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
+ full_node_1 = full_node_api_1.full_node
+
+ for block in blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ spend_block = blocks[1]
+
+ spend_coin = None
+ for coin in list(spend_block.get_included_reward_coins()):
+ if coin.puzzle_hash == coinbase_puzzlehash:
+ spend_coin = coin
+
+ spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spend_coin)
+ spend_bundle_double = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spend_coin)
+
+ block_spendbundle = SpendBundle.aggregate([spend_bundle, spend_bundle_double])
+
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ block_list_input=blocks,
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=block_spendbundle,
+ guarantee_block=True,
+ )
+
+ next_block = new_blocks[-1]
+ res, err, _ = await full_node_1.blockchain.receive_block(next_block)
+ assert res == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.DUPLICATE_OUTPUT
+
+ @pytest.mark.asyncio
+ async def test_validate_blockchain_with_reorg_double_spend(self, two_nodes):
+ num_blocks = 10
+ wallet_a = WALLET_A
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
+ receiver_puzzlehash = BURN_PUZZLE_HASH
+
+ blocks = bt.get_consecutive_blocks(
+ num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_block=True
+ )
+ full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
+
+ for block in blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ spend_block = blocks[1]
+
+ spend_coin = None
+ for coin in list(spend_block.get_included_reward_coins()):
+ if coin.puzzle_hash == coinbase_puzzlehash:
+ spend_coin = coin
+
+ spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spend_coin)
+
+ blocks_spend = bt.get_consecutive_blocks(
+ 1, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_block=True, transaction_data=spend_bundle
+ )
+ # Move chain to height 10, with a spend at height 10
+ for block in blocks_spend:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ # Reorg at height 5, add up to and including height 12
+ new_blocks = bt.get_consecutive_blocks(
+ 7,
+ blocks[:6],
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ guarantee_block=True,
+ seed=b"another seed",
+ )
+
+ for block in new_blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ # Spend the same coin in the new reorg chain at height 13
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ new_blocks,
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ guarantee_block=True,
+ transaction_data=spend_bundle,
+ )
+
+ res, err, _ = await full_node_api_1.full_node.blockchain.receive_block(new_blocks[-1])
+ assert err is None
+ assert res == ReceiveBlockResult.NEW_PEAK
+
+ # But can't spend it twice
+ new_blocks_double = bt.get_consecutive_blocks(
+ 1,
+ new_blocks,
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ guarantee_block=True,
+ transaction_data=spend_bundle,
+ )
+
+ res, err, _ = await full_node_api_1.full_node.blockchain.receive_block(new_blocks_double[-1])
+ assert err is Err.DOUBLE_SPEND
+ assert res == ReceiveBlockResult.INVALID_BLOCK
+
+ # Now test Reorg at block 5, same spend at block height 12
+ new_blocks_reorg = bt.get_consecutive_blocks(
+ 1,
+ new_blocks[:12],
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ guarantee_block=True,
+ transaction_data=spend_bundle,
+ seed=b"spend at 12 is ok",
+ )
+ for block in new_blocks_reorg:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ # Spend at height 13 is also OK (same height)
+ new_blocks_reorg = bt.get_consecutive_blocks(
+ 1,
+ new_blocks[:13],
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ guarantee_block=True,
+ transaction_data=spend_bundle,
+ seed=b"spend at 13 is ok",
+ )
+ for block in new_blocks_reorg:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ # Spend at height 14 is not OK (already spend)
+ new_blocks_reorg = bt.get_consecutive_blocks(
+ 1,
+ new_blocks[:14],
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ guarantee_block=True,
+ transaction_data=spend_bundle,
+ seed=b"spend at 14 is double spend",
+ )
+ with pytest.raises(ConsensusError):
+ for block in new_blocks_reorg:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ @pytest.mark.asyncio
+ async def test_validate_blockchain_spend_reorg_coin(self, two_nodes):
+ num_blocks = 10
+ wallet_a = WALLET_A
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
+ receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
+ receiver_2_puzzlehash = WALLET_A_PUZZLE_HASHES[2]
+ receiver_3_puzzlehash = WALLET_A_PUZZLE_HASHES[3]
+
+ blocks = bt.get_consecutive_blocks(
+ num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_block=True
+ )
+ full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
+
+ for block in blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ spend_block = blocks[1]
+
+ spend_coin = None
+ for coin in list(spend_block.get_included_reward_coins()):
+ if coin.puzzle_hash == coinbase_puzzlehash:
+ spend_coin = coin
+
+ spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash, spend_coin)
+
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ blocks[:5],
+ seed=b"spend_reorg_coin",
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=spend_bundle,
+ guarantee_block=True,
+ )
+
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
+
+ coin_2 = None
+ for coin in new_blocks[-1].additions():
+ if coin.puzzle_hash == receiver_1_puzzlehash:
+ coin_2 = coin
+ break
+ assert coin_2 is not None
+
+ spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_2_puzzlehash, coin_2)
+
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ new_blocks[:6],
+ seed=b"spend_reorg_coin",
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=spend_bundle,
+ guarantee_block=True,
+ )
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
+
+ coin_3 = None
+ for coin in new_blocks[-1].additions():
+ if coin.puzzle_hash == receiver_2_puzzlehash:
+ coin_3 = coin
+ break
+ assert coin_3 is not None
+
+ spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_3_puzzlehash, coin_3)
+
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ new_blocks[:7],
+ seed=b"spend_reorg_coin",
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=spend_bundle,
+ guarantee_block=True,
+ )
+
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
+
+ coin_4 = None
+ for coin in new_blocks[-1].additions():
+ if coin.puzzle_hash == receiver_3_puzzlehash:
+ coin_4 = coin
+ break
+ assert coin_4 is not None
+
+ @pytest.mark.asyncio
+ async def test_validate_blockchain_spend_reorg_cb_coin(self, two_nodes):
+ num_blocks = 15
+ wallet_a = WALLET_A
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
+ receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
+
+ blocks = bt.get_consecutive_blocks(num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash)
+ full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
+
+ for block in blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ # Spends a coinbase created in reorg
+ new_blocks = bt.get_consecutive_blocks(
+ 5,
+ blocks[:6],
+ seed=b"reorg cb coin",
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ guarantee_block=True,
+ )
+
+ for block in new_blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ spend_block = new_blocks[-1]
+ spend_coin = None
+ for coin in list(spend_block.get_included_reward_coins()):
+ if coin.puzzle_hash == coinbase_puzzlehash:
+ spend_coin = coin
+ spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash, spend_coin)
+
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ new_blocks,
+ seed=b"reorg cb coin",
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=spend_bundle,
+ guarantee_block=True,
+ )
+
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
+
+ coins_created = []
+ for coin in new_blocks[-1].additions():
+ if coin.puzzle_hash == receiver_1_puzzlehash:
+ coins_created.append(coin)
+ assert len(coins_created) == 1
+
+ @pytest.mark.asyncio
+ async def test_validate_blockchain_spend_reorg_since_genesis(self, two_nodes):
+ num_blocks = 10
+ wallet_a = WALLET_A
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
+ receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
+
+ blocks = bt.get_consecutive_blocks(
+ num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_block=True
+ )
+ full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
+
+ for block in blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ spend_block = blocks[-1]
+ spend_coin = None
+ for coin in list(spend_block.get_included_reward_coins()):
+ if coin.puzzle_hash == coinbase_puzzlehash:
+ spend_coin = coin
+ spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_1_puzzlehash, spend_coin)
+
+ new_blocks = bt.get_consecutive_blocks(
+ 1, blocks, seed=b"", farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=spend_bundle
+ )
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
+
+ # Spends a coin in a genesis reorg, that was already spent
+ new_blocks = bt.get_consecutive_blocks(
+ 12,
+ [],
+ seed=b"reorg since genesis",
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ )
+ for block in new_blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ new_blocks,
+ seed=b"reorg since genesis",
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=spend_bundle,
+ )
+
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(new_blocks[-1]))
+
+ @pytest.mark.asyncio
+ async def test_assert_my_coin_id(self, two_nodes):
+ num_blocks = 10
+ wallet_a = WALLET_A
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
+ receiver_puzzlehash = BURN_PUZZLE_HASH
+
+ # Farm blocks
+ blocks = bt.get_consecutive_blocks(
+ num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_block=True
+ )
+ full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes
+ full_node_1 = full_node_api_1.full_node
+
+ for block in blocks:
+ await full_node_api_1.full_node.respond_sub_block(full_node_protocol.RespondSubBlock(block))
+
+ # Coinbase that gets spent
+
+ spend_block = blocks[1]
+ bad_block = blocks[2]
+ spend_coin = None
+ bad_spend_coin = None
+ for coin in list(spend_block.get_included_reward_coins()):
+ if coin.puzzle_hash == coinbase_puzzlehash:
+ spend_coin = coin
+ for coin in list(bad_block.get_included_reward_coins()):
+ if coin.puzzle_hash == coinbase_puzzlehash:
+ bad_spend_coin = coin
+ valid_cvp = ConditionVarPair(ConditionOpcode.ASSERT_MY_COIN_ID, spend_coin.name(), None)
+ valid_dic = {valid_cvp.opcode: [valid_cvp]}
+ bad_cvp = ConditionVarPair(
+ ConditionOpcode.ASSERT_MY_COIN_ID,
+ bad_spend_coin.name(),
+ None,
+ )
+
+ bad_dic = {bad_cvp.opcode: [bad_cvp]}
+ bad_spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spend_coin, bad_dic)
+
+ valid_spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spend_coin, valid_dic)
+
+ assert bad_spend_bundle is not None
+ assert valid_spend_bundle is not None
+
+ # Invalid block bundle
+ # Create another block that includes our transaction
+ invalid_new_blocks = bt.get_consecutive_blocks(
+ 1,
+ blocks,
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=bad_spend_bundle,
+ guarantee_block=True,
+ )
+
+ # Try to validate that block
+ res, err, _ = await full_node_1.blockchain.receive_block(invalid_new_blocks[-1])
+ assert res == ReceiveBlockResult.INVALID_BLOCK
+ assert err == Err.ASSERT_MY_COIN_ID_FAILED
+
+ # Valid block bundle
+ # Create another block that includes our transaction
+ new_blocks = bt.get_consecutive_blocks(
+ 1,
+ blocks,
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
+ transaction_data=valid_spend_bundle,
+ guarantee_block=True,
+ )
+ res, err, _ = await full_node_1.blockchain.receive_block(new_blocks[-1])
+ assert res == ReceiveBlockResult.NEW_PEAK
+ assert err is None
+
+
+# #
+# # @pytest.mark.asyncio
# async def test_assert_coin_consumed(self, two_nodes):
#
# num_blocks = 10
diff --git a/tests/full_node/test_full_node.py b/tests/full_node/test_full_node.py
index a0d43d7e1c..115d6fc2ec 100644
--- a/tests/full_node/test_full_node.py
+++ b/tests/full_node/test_full_node.py
@@ -157,9 +157,7 @@ class TestFullNodeProtocol:
async def have_msgs():
await full_node_2.full_node.full_node_peers.address_manager.add_to_new_table(
- [
- TimestampedPeerInfo("127.0.0.1", uint16(1000), uint64(int(time.time())) - 1000),
- ],
+ [TimestampedPeerInfo("127.0.0.1", uint16(1000), uint64(int(time.time())) - 1000)],
None,
)
msg = await full_node_2.full_node.full_node_peers.request_peers(PeerInfo("[::1]", server_2._port))
diff --git a/tests/full_node/test_mempool.py b/tests/full_node/test_mempool.py
index 622bd183d8..1e8298e57c 100644
--- a/tests/full_node/test_mempool.py
+++ b/tests/full_node/test_mempool.py
@@ -10,9 +10,7 @@ from src.types.coin_solution import CoinSolution
from src.types.condition_var_pair import ConditionVarPair
from src.types.condition_opcodes import ConditionOpcode
from src.types.spend_bundle import SpendBundle
-from src.util.condition_tools import (
- conditions_for_solution,
-)
+from src.util.condition_tools import conditions_for_solution
from src.util.clvm import int_to_bytes
from src.util.ints import uint64
from tests.full_node.test_full_node import connect_and_get_peer, node_height_at_least
diff --git a/tests/rpc/test_farmer_harvester_rpc.py b/tests/rpc/test_farmer_harvester_rpc.py
index 2f13499f18..5f70da8d32 100644
--- a/tests/rpc/test_farmer_harvester_rpc.py
+++ b/tests/rpc/test_farmer_harvester_rpc.py
@@ -75,7 +75,6 @@ class TestRpc:
await time_out_assert(15, have_connections, True)
assert (await client.get_signage_point(std_hash(b"2"))) is None
- print(await client.get_signage_points())
assert len(await client.get_signage_points()) == 0
async def have_signage_points():
@@ -119,7 +118,6 @@ class TestRpc:
res_2 = await client_2.get_plots()
assert len(res_2["plots"]) == num_plots
- print(await client_2.get_plot_directories())
assert len(await client_2.get_plot_directories()) == 1
await client_2.add_plot_directory(str(plot_dir))
@@ -134,7 +132,6 @@ class TestRpc:
assert len(res_3["plots"]) == num_plots
await client_2.remove_plot_directory(str(plot_dir))
- print(await client_2.get_plot_directories())
assert len(await client_2.get_plot_directories()) == 1
finally:
diff --git a/tests/test_simulation.py b/tests/test_simulation.py
index cc129e21b4..623e577b5b 100644
--- a/tests/test_simulation.py
+++ b/tests/test_simulation.py
@@ -1,5 +1,4 @@
import pytest
-
from tests.full_node.test_full_sync import node_height_at_least
from tests.setup_nodes import setup_full_system, test_constants
from src.util.ints import uint16
@@ -33,7 +32,7 @@ class TestSimulation:
node1, node2, _, _, _, _, _, server1 = simulation
await server1.start_client(PeerInfo("localhost", uint16(21238)))
# Use node2 to test node communication, since only node1 extends the chain.
- await time_out_assert(1000, node_height_at_least, True, node2, 10)
+ await time_out_assert(1000, node_height_at_least, True, node2, 7)
# Wait additional 2 minutes to get a compact block.
# max_height = node1.full_node.blockchain.lca_block.height
diff --git a/tests/time_out_assert.py b/tests/time_out_assert.py
index f781651a1e..2db0b9e061 100644
--- a/tests/time_out_assert.py
+++ b/tests/time_out_assert.py
@@ -1,7 +1,10 @@
import asyncio
import time
+import logging
from typing import Callable
+log = logging.getLogger(__name__)
+
async def time_out_assert_custom_interval(timeout: int, interval, function, value=True, *args, **kwargs):
start = time.time()
@@ -40,7 +43,7 @@ def time_out_messages(incoming_queue: asyncio.Queue, msg_name: str, count: int =
for _ in range(count):
response = (await incoming_queue.get())[0].msg.function
if response != msg_name:
- print(f"Error, found {response} instead of {msg_name}")
+ log.error(f"Error, found {response} instead of {msg_name}")
return False
return True