chia-blockchain/chia/data_layer/data_layer.py

140 lines
5.2 KiB
Python
Raw Normal View History

import logging
2021-09-17 17:30:14 +03:00
from pathlib import Path
2021-10-16 00:14:34 +03:00
from typing import Any, Callable, Dict, List, Optional
2021-09-17 15:03:48 +03:00
import aiosqlite
from chia.daemon.keychain_proxy import KeychainProxyConnectionFailure
2021-10-13 21:18:00 +03:00
from chia.data_layer.data_layer_wallet import DataLayerWallet
from chia.data_layer.data_store import DataStore
2021-09-29 02:37:50 +03:00
from chia.server.server import ChiaServer
2021-10-13 21:18:00 +03:00
from chia.types.blockchain_format.sized_bytes import bytes32
2021-11-10 17:12:11 +03:00
from chia.util.config import load_config
2021-09-17 17:30:14 +03:00
from chia.util.db_wrapper import DBWrapper
2021-10-27 14:58:36 +03:00
from chia.util.ints import uint64
from chia.util.path import mkdir, path_from_root
from chia.wallet.wallet_node import WalletNode
2021-09-17 15:03:48 +03:00
class DataLayer:
data_store: DataStore
2021-09-17 17:30:14 +03:00
db_wrapper: DBWrapper
db_path: Path
connection: aiosqlite.Connection
2021-10-04 01:20:18 +03:00
config: Dict[str, Any]
log: logging.Logger
2021-10-13 21:18:00 +03:00
wallet: DataLayerWallet
wallet_node: Optional[WalletNode]
2021-10-04 01:20:18 +03:00
state_changed_callback: Optional[Callable[..., object]]
initialized: bool
2021-09-17 15:03:48 +03:00
def __init__(
self,
2021-09-17 17:30:14 +03:00
root_path: Path,
wallet_node: WalletNode,
name: Optional[str] = None,
):
if name == "":
# TODO: If no code depends on "" counting as 'unspecified' then we do not
# need this.
name = None
2021-11-10 17:12:11 +03:00
config = load_config(root_path, "config.yaml", "data_layer")
self.initialized = False
2021-10-04 00:35:44 +03:00
self.config = config
self.wallet_node = wallet_node
self.log = logging.getLogger(name if name is None else __name__)
db_path_replaced: str = config["database_path"].replace("CHALLENGE", config["selected_network"])
self.db_path = path_from_root(root_path, db_path_replaced)
mkdir(self.db_path.parent)
2021-09-17 15:03:48 +03:00
2021-09-29 02:37:50 +03:00
def _set_state_changed_callback(self, callback: Callable[..., object]) -> None:
self.state_changed_callback = callback
def set_server(self, server: ChiaServer) -> None:
self.server = server
2021-09-17 15:03:48 +03:00
async def _start(self) -> bool:
2021-10-04 00:35:44 +03:00
# create the store (db) and data store instance
assert self.wallet_node
try:
private_key = await self.wallet_node.get_key_for_fingerprint(None)
except KeychainProxyConnectionFailure:
self.log.error("Failed to connect to keychain service")
return False
if private_key is None:
self.logged_in = False
return False
self.connection = await aiosqlite.connect(self.db_path)
2021-09-17 17:30:14 +03:00
self.db_wrapper = DBWrapper(self.connection)
self.data_store = await DataStore.create(self.db_wrapper)
assert self.wallet_node.wallet_state_manager
main_wallet = self.wallet_node.wallet_state_manager.main_wallet
amount = uint64(1) # todo what should amount be ?
async with self.wallet_node.wallet_state_manager.lock:
2021-11-30 00:17:39 +03:00
creation_record = await self.wallet.create_new_dl_wallet(
self.wallet_node.wallet_state_manager, main_wallet, amount, None
)
2021-12-01 02:15:16 +03:00
self.wallet = creation_record.item
2021-10-04 00:35:44 +03:00
self.initialized = True
return True
2021-09-17 15:31:28 +03:00
2021-09-29 02:37:50 +03:00
def _close(self) -> None:
# TODO: review for anything else we need to do here
2021-10-04 00:35:44 +03:00
# self._shut_down = True
pass
2021-09-29 02:37:50 +03:00
async def _await_closed(self) -> None:
await self.connection.close()
2021-10-13 21:18:00 +03:00
async def create_store(self) -> bytes32:
assert self.wallet.dl_info.origin_coin
tree_id = self.wallet.dl_info.origin_coin.name()
2021-10-27 14:58:36 +03:00
res = await self.data_store.create_tree(tree_id)
if res is None:
self.log.fatal("failed creating store")
2021-10-27 14:58:36 +03:00
return tree_id
2021-10-13 21:18:00 +03:00
async def insert(
self,
tree_id: bytes32,
changelist: List[Dict[str, Any]],
) -> bool:
for change in changelist:
if change["action"] == "insert":
key = change["key"]
value = change["value"]
reference_node_hash = change.get("reference_node_hash")
side = change.get("side")
if reference_node_hash or side:
await self.data_store.insert(key, value, tree_id, reference_node_hash, side)
await self.data_store.autoinsert(key, value, tree_id)
2021-10-13 21:18:00 +03:00
else:
assert change["action"] == "delete"
key = change["key"]
2021-10-13 21:18:00 +03:00
await self.data_store.delete(key, tree_id)
2021-10-27 14:58:36 +03:00
root = await self.data_store.get_tree_root(tree_id)
assert root.node_hash
res = await self.wallet.create_update_state_spend(root.node_hash)
assert res
2021-10-13 21:18:00 +03:00
# todo need to mark data as pending and change once tx is confirmed
return True
2021-10-18 12:42:55 +03:00
async def get_value(self, store_id: bytes32, key: bytes32) -> bytes32:
res = await self.data_store.get_node_by_key(tree_id=store_id, key=key)
if res is None:
self.log.error("Failed to create tree")
return res.value
async def get_pairs(self, store_id: bytes32) -> bytes32:
res = await self.data_store.get_pairs(store_id)
if res is None:
2021-10-13 21:18:00 +03:00
self.log.error("Failed to create tree")
2021-10-18 12:42:55 +03:00
return res
2021-10-13 21:18:00 +03:00
2021-10-27 14:58:36 +03:00
async def get_ancestors(self, node_hash: bytes32, store_id: bytes32) -> bytes32:
res = await self.data_store.get_ancestors(store_id, node_hash)
if res is None:
self.log.error("Failed to create tree")
return res