mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-19 14:48:38 +03:00
Comments, Windows->Microsoft, and fix tests
This commit is contained in:
parent
67cb6359ac
commit
f721c58ba5
@ -98,7 +98,7 @@ This will require multiple reboots. From an Administrator PowerShell
|
||||
`Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux`
|
||||
and then
|
||||
`Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform`.
|
||||
Once that is complete, install Ubuntu 18.04 LTS from the Windows Store.
|
||||
Once that is complete, install Ubuntu 18.04 LTS from the Microsoft Store.
|
||||
```bash
|
||||
# Upgrade to 19.x
|
||||
sudo nano /etc/update-manager/release-upgrades
|
||||
|
@ -11,17 +11,7 @@ from src.server.connection import NodeType
|
||||
from src.types.header_block import HeaderBlock
|
||||
from src.rpc.rpc_client import RpcClient
|
||||
from src.util.byte_types import hexstr_to_bytes
|
||||
|
||||
|
||||
def str2bool(v: str) -> bool:
|
||||
if isinstance(v, bool):
|
||||
return v
|
||||
if v.lower() in ("yes", "true", "t", "y", "1"):
|
||||
return True
|
||||
elif v.lower() in ("no", "false", "f", "n", "0"):
|
||||
return False
|
||||
else:
|
||||
raise argparse.ArgumentTypeError("Boolean value expected.")
|
||||
from src.util.config import str2bool
|
||||
|
||||
|
||||
async def async_main():
|
||||
|
@ -5,23 +5,12 @@ from blspy import PrivateKey, ExtendedPrivateKey
|
||||
from src.path import mkdir, path_from_root
|
||||
from src.pool import create_puzzlehash_for_pk
|
||||
from src.types.hashable.BLSSignature import BLSPublicKey
|
||||
from src.util.config import load_config, save_config
|
||||
from src.util.config import load_config, save_config, str2bool
|
||||
|
||||
|
||||
key_config_filename = path_from_root() / "config" / "keys.yaml"
|
||||
|
||||
|
||||
def str2bool(v: str) -> bool:
|
||||
if isinstance(v, bool):
|
||||
return v
|
||||
if v.lower() in ("yes", "true", "t", "y", "1"):
|
||||
return True
|
||||
elif v.lower() in ("no", "false", "f", "n", "0"):
|
||||
return False
|
||||
else:
|
||||
raise argparse.ArgumentTypeError("Boolean value expected.")
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Allows replacing keys of farmer, harvester, and pool, all default to True.
|
||||
|
@ -214,7 +214,9 @@ class RpcApiHandler:
|
||||
return obj_to_response(max_tip)
|
||||
|
||||
|
||||
async def start_rpc_server(full_node: FullNode, stop_node_cb: Callable, rpc_port: int):
|
||||
async def start_rpc_server(
|
||||
full_node: FullNode, stop_node_cb: Callable, rpc_port: uint16
|
||||
):
|
||||
"""
|
||||
Starts an HTTP server with the following RPC methods, to be used by local clients to
|
||||
query the node.
|
||||
@ -238,7 +240,7 @@ async def start_rpc_server(full_node: FullNode, stop_node_cb: Callable, rpc_port
|
||||
|
||||
runner = web.AppRunner(app, access_log=None)
|
||||
await runner.setup()
|
||||
site = web.TCPSite(runner, "localhost", rpc_port)
|
||||
site = web.TCPSite(runner, "localhost", int(rpc_port))
|
||||
await site.start()
|
||||
|
||||
async def cleanup():
|
||||
|
@ -27,6 +27,9 @@ class TransactionRecord(Streamable):
|
||||
additions: List[Coin]
|
||||
removals: List[Coin]
|
||||
wallet_id: uint64
|
||||
|
||||
# Represents the list of peers that we sent the transaction to, whether each one
|
||||
# included it in the mempool, and what the error message (if any) was
|
||||
sent_to: List[Tuple[str, uint8, Optional[str]]]
|
||||
|
||||
def name(self) -> bytes32:
|
||||
|
@ -8,7 +8,7 @@ from src.wallet.util.wallet_types import WalletType
|
||||
@streamable
|
||||
class WalletInfo(Streamable):
|
||||
"""
|
||||
Wrapper around data that
|
||||
# TODO(straya): describe
|
||||
"""
|
||||
|
||||
id: int
|
||||
|
@ -41,20 +41,35 @@ class WalletNode:
|
||||
private_key: ExtendedPrivateKey
|
||||
key_config: Dict
|
||||
config: Dict
|
||||
constants: Dict
|
||||
server: Optional[ChiaServer]
|
||||
wallet_state_manager: WalletStateManager
|
||||
log: logging.Logger
|
||||
|
||||
# Maintains the state of the wallet (blockchain and transactions), handles DB connections
|
||||
wallet_state_manager: WalletStateManager
|
||||
main_wallet: Wallet
|
||||
wallets: Dict[int, Any]
|
||||
|
||||
# Maintains headers recently received. Once the desired removals and additions are downloaded,
|
||||
# the data is persisted in the WalletStateManager. These variables are also used to store
|
||||
# temporary sync data.
|
||||
cached_blocks: Dict[bytes32, Tuple[BlockRecord, HeaderBlock]]
|
||||
cached_removals: Dict[bytes32, List[bytes32]]
|
||||
cached_additions: Dict[bytes32, List[Coin]]
|
||||
|
||||
# Hashes of the PoT and PoSpace for all blocks (including occasional difficulty adjustments)
|
||||
proof_hashes: List[Tuple[bytes32, Optional[uint64], Optional[uint64]]]
|
||||
|
||||
# List of header hashes downloaded during sync
|
||||
header_hashes: List[bytes32]
|
||||
header_hashes_error: bool
|
||||
|
||||
# Event to signal when a block is received (during sync)
|
||||
potential_blocks_received: Dict[uint32, asyncio.Event]
|
||||
potential_header_hashes: Dict[uint32, bytes32]
|
||||
constants: Dict
|
||||
|
||||
# How far away from LCA we must be to perform a full sync. Before then, do a short sync,
|
||||
# which is consecutive requests for the previous block
|
||||
short_sync_threshold: int
|
||||
_shut_down: bool
|
||||
|
||||
@ -219,6 +234,9 @@ class WalletNode:
|
||||
async def respond_peers(
|
||||
self, request: full_node_protocol.RespondPeers
|
||||
) -> OutboundMessageGenerator:
|
||||
"""
|
||||
We have received a list of full node peers that we can connect to.
|
||||
"""
|
||||
if self.server is None:
|
||||
return
|
||||
conns = self.server.global_connections
|
||||
@ -248,7 +266,7 @@ class WalletNode:
|
||||
async def _sync(self):
|
||||
"""
|
||||
Wallet has fallen far behind (or is starting up for the first time), and must be synced
|
||||
up to the tip of the blockchain
|
||||
up to the LCA of the blockchain.
|
||||
"""
|
||||
# 1. Get all header hashes
|
||||
self.header_hashes = []
|
||||
@ -286,6 +304,7 @@ class WalletNode:
|
||||
self.header_hashes
|
||||
)
|
||||
fork_point_hash: bytes32 = self.header_hashes[fork_point_height]
|
||||
|
||||
# Sync a little behind, in case there is a short reorg
|
||||
tip_height = (
|
||||
len(self.header_hashes) - 5
|
||||
@ -337,12 +356,13 @@ class WalletNode:
|
||||
list(
|
||||
set(
|
||||
random.choices(
|
||||
heights, difficulty_weights, k=min(50, len(heights))
|
||||
heights, difficulty_weights, k=min(100, len(heights))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
query_heights: List[uint32] = []
|
||||
|
||||
for odd_height in query_heights_odd:
|
||||
query_heights += [uint32(odd_height - 1), odd_height]
|
||||
|
||||
@ -546,6 +566,14 @@ class WalletNode:
|
||||
async def _block_finished(
|
||||
self, block_record: BlockRecord, header_block: HeaderBlock
|
||||
):
|
||||
"""
|
||||
This is called when we have finished a block (which means we have downloaded the header,
|
||||
as well as the relevant additions and removals for the wallets). If a sync block is finished,
|
||||
we don't add it to the database, but instead just set the potential_blocks_received.
|
||||
During normal operation (not sync) we add block to the WSM (database), if the previous block
|
||||
is present. If the previous block is not present, we cached the current block, and request
|
||||
the previous.
|
||||
"""
|
||||
if self.wallet_state_manager.sync_mode:
|
||||
self.potential_blocks_received[uint32(block_record.height)].set()
|
||||
self.potential_header_hashes[block_record.height] = block_record.header_hash
|
||||
@ -616,6 +644,10 @@ class WalletNode:
|
||||
async def transaction_ack_with_peer_name(
|
||||
self, ack: wallet_protocol.TransactionAck, name: str
|
||||
):
|
||||
"""
|
||||
This is an ack for our previous SendTransaction call. This removes the transaction from
|
||||
the send queue if we have sent it to enough nodes.
|
||||
"""
|
||||
if ack.status == MempoolInclusionStatus.SUCCESS:
|
||||
self.log.info(
|
||||
f"SpendBundle has been received and accepted to mempool by the FullNode. {ack}"
|
||||
@ -639,6 +671,9 @@ class WalletNode:
|
||||
async def respond_all_proof_hashes(
|
||||
self, response: wallet_protocol.RespondAllProofHashes
|
||||
):
|
||||
"""
|
||||
Receipt of proof hashes, used during sync for interactive weight verification protocol.
|
||||
"""
|
||||
if not self.wallet_state_manager.sync_mode:
|
||||
self.log.warning("Receiving proof hashes while not syncing.")
|
||||
return
|
||||
@ -648,6 +683,10 @@ class WalletNode:
|
||||
async def respond_all_header_hashes_after(
|
||||
self, response: wallet_protocol.RespondAllHeaderHashesAfter
|
||||
):
|
||||
"""
|
||||
Response containing all header hashes after a point. This is used to find the fork
|
||||
point between our current blockchain, and the current heaviest tip.
|
||||
"""
|
||||
if not self.wallet_state_manager.sync_mode:
|
||||
self.log.warning("Receiving header hashes while not syncing.")
|
||||
return
|
||||
@ -657,11 +696,18 @@ class WalletNode:
|
||||
async def reject_all_header_hashes_after_request(
|
||||
self, response: wallet_protocol.RejectAllHeaderHashesAfterRequest
|
||||
):
|
||||
"""
|
||||
Error in requesting all header hashes.
|
||||
"""
|
||||
self.log.error("All header hashes after request rejected")
|
||||
self.header_hashes_error = True
|
||||
|
||||
@api_request
|
||||
async def new_lca(self, request: wallet_protocol.NewLCA):
|
||||
"""
|
||||
Notification from full node that a new LCA (Least common ancestor of the three blockchain
|
||||
tips) has been added to the full node.
|
||||
"""
|
||||
if self.wallet_state_manager.sync_mode:
|
||||
return
|
||||
# If already seen LCA, ignore.
|
||||
@ -698,6 +744,10 @@ class WalletNode:
|
||||
|
||||
@api_request
|
||||
async def respond_header(self, response: wallet_protocol.RespondHeader):
|
||||
"""
|
||||
The full node responds to our RequestHeader call. We cannot finish this block
|
||||
until we have the required additions / removals for our wallets.
|
||||
"""
|
||||
block = response.header_block
|
||||
# If we already have, return
|
||||
if block.header_hash in self.wallet_state_manager.block_records:
|
||||
@ -717,7 +767,7 @@ class WalletNode:
|
||||
)
|
||||
finish_block = True
|
||||
|
||||
# If we have transactions, fetch adds/deletes
|
||||
# If the block has transactions, fetch adds/deletes
|
||||
if response.transactions_filter is not None:
|
||||
# Caches the block so we can finalize it when additions and removals arrive
|
||||
self.cached_blocks[block.header_hash] = (block_record, block)
|
||||
@ -755,11 +805,18 @@ class WalletNode:
|
||||
async def reject_header_request(
|
||||
self, response: wallet_protocol.RejectHeaderRequest
|
||||
):
|
||||
"""
|
||||
The full node has rejected our request for a header.
|
||||
"""
|
||||
# TODO(mariano): implement
|
||||
self.log.error("Header request rejected")
|
||||
|
||||
@api_request
|
||||
async def respond_removals(self, response: wallet_protocol.RespondRemovals):
|
||||
"""
|
||||
The full node has responded with the removals for a block. We will use this
|
||||
to try to finish the block, and add it to the state.
|
||||
"""
|
||||
if response.header_hash not in self.cached_blocks:
|
||||
self.log.warning("Do not have header for removals")
|
||||
return
|
||||
@ -768,7 +825,8 @@ class WalletNode:
|
||||
|
||||
removals: List[bytes32]
|
||||
if response.proofs is None:
|
||||
# Find our removals
|
||||
# If there are no proofs, it means all removals were returned in the response.
|
||||
# we must find the ones relevant to our wallets.
|
||||
all_coins: List[Coin] = []
|
||||
for coin_name, coin in response.coins:
|
||||
if coin is not None:
|
||||
@ -789,6 +847,8 @@ class WalletNode:
|
||||
assert header_block.header.data.removals_root == removals_root
|
||||
|
||||
else:
|
||||
# This means the full node has responded only with the relevant removals
|
||||
# for our wallet. Each merkle proof must be verified.
|
||||
removals = []
|
||||
assert len(response.coins) == len(response.proofs)
|
||||
for i in range(len(response.coins)):
|
||||
@ -796,12 +856,14 @@ class WalletNode:
|
||||
assert response.coins[i][0] == response.proofs[i][0]
|
||||
coin = response.coins[i][1]
|
||||
if coin is None:
|
||||
# Verifies merkle proof of exclusion
|
||||
assert confirm_not_included_already_hashed(
|
||||
header_block.header.data.removals_root,
|
||||
response.coins[i][0],
|
||||
response.proofs[i][1],
|
||||
)
|
||||
else:
|
||||
# Verifies merkle proof of inclusion of coin name
|
||||
assert response.coins[i][0] == coin.name()
|
||||
assert confirm_included_already_hashed(
|
||||
header_block.header.data.removals_root,
|
||||
@ -833,11 +895,18 @@ class WalletNode:
|
||||
async def reject_removals_request(
|
||||
self, response: wallet_protocol.RejectRemovalsRequest
|
||||
):
|
||||
"""
|
||||
The full node has rejected our request for removals.
|
||||
"""
|
||||
# TODO(mariano): implement
|
||||
self.log.error("Removals request rejected")
|
||||
|
||||
@api_request
|
||||
async def respond_additions(self, response: wallet_protocol.RespondAdditions):
|
||||
"""
|
||||
The full node has responded with the additions for a block. We will use this
|
||||
to try to finish the block, and add it to the state.
|
||||
"""
|
||||
if response.header_hash not in self.cached_blocks:
|
||||
self.log.warning("Do not have header for additions")
|
||||
return
|
||||
@ -846,7 +915,8 @@ class WalletNode:
|
||||
|
||||
additions: List[Coin]
|
||||
if response.proofs is None:
|
||||
# Find our removals
|
||||
# If there are no proofs, it means all additions were returned in the response.
|
||||
# we must find the ones relevant to our wallets.
|
||||
all_coins: List[Coin] = []
|
||||
for puzzle_hash, coin_list_0 in response.coins:
|
||||
all_coins += coin_list_0
|
||||
@ -865,6 +935,8 @@ class WalletNode:
|
||||
if header_block.header.data.additions_root != additions_root:
|
||||
return
|
||||
else:
|
||||
# This means the full node has responded only with the relevant additions
|
||||
# for our wallet. Each merkle proof must be verified.
|
||||
additions = []
|
||||
assert len(response.coins) == len(response.proofs)
|
||||
for i in range(len(response.coins)):
|
||||
@ -919,5 +991,8 @@ class WalletNode:
|
||||
async def reject_additions_request(
|
||||
self, response: wallet_protocol.RejectAdditionsRequest
|
||||
):
|
||||
"""
|
||||
The full node has rejected our request for additions.
|
||||
"""
|
||||
# TODO(mariano): implement
|
||||
self.log.error("Additions request rejected")
|
||||
|
@ -190,7 +190,10 @@ class WalletStateManager:
|
||||
|
||||
return uint64(amount)
|
||||
|
||||
async def does_coin_belongs_to_wallet(self, coin: Coin, wallet_id: int) -> bool:
|
||||
async def does_coin_belong_to_wallet(self, coin: Coin, wallet_id: int) -> bool:
|
||||
"""
|
||||
Returns true if we have the key for this coin.
|
||||
"""
|
||||
info = await self.puzzle_store.wallet_info_for_puzzle_hash(coin.puzzle_hash)
|
||||
|
||||
if info is None:
|
||||
@ -214,10 +217,10 @@ class WalletStateManager:
|
||||
|
||||
for record in unconfirmed_tx:
|
||||
for coin in record.additions:
|
||||
if await self.does_coin_belongs_to_wallet(coin, wallet_id):
|
||||
if await self.does_coin_belong_to_wallet(coin, wallet_id):
|
||||
addition_amount += coin.amount
|
||||
for coin in record.removals:
|
||||
if await self.does_coin_belongs_to_wallet(coin, wallet_id):
|
||||
if await self.does_coin_belong_to_wallet(coin, wallet_id):
|
||||
removal_amount += coin.amount
|
||||
|
||||
result = confirmed - removal_amount + addition_amount
|
||||
|
@ -14,7 +14,6 @@ class WalletStore:
|
||||
"""
|
||||
|
||||
db_connection: aiosqlite.Connection
|
||||
# Whether or not we are syncing
|
||||
coin_record_cache: Dict[str, WalletCoinRecord]
|
||||
cache_size: uint32
|
||||
|
||||
@ -318,6 +317,11 @@ class WalletStore:
|
||||
await self.db_connection.commit()
|
||||
|
||||
async def get_lca_path(self) -> Dict[bytes32, BlockRecord]:
|
||||
"""
|
||||
Returns block records representing the blockchain from the genesis
|
||||
block up to the LCA (least common ancestor). Note that the DB also
|
||||
contains many blocks not on this path, due to reorgs.
|
||||
"""
|
||||
cursor = await self.db_connection.execute(
|
||||
"SELECT * from block_records WHERE in_lca_path=1"
|
||||
)
|
||||
@ -366,6 +370,10 @@ class WalletStore:
|
||||
await self.db_connection.commit()
|
||||
|
||||
async def remove_blocks_from_path(self, from_height: uint32) -> None:
|
||||
"""
|
||||
When rolling back the LCA, sets in_lca_path to 0 for blocks over the given
|
||||
height. This is used during reorgs to rollback the current lca.
|
||||
"""
|
||||
cursor = await self.db_connection.execute(
|
||||
"UPDATE block_records SET in_lca_path=0 WHERE height>?", (from_height,),
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user