2021-09-16 04:31:41 +03:00
|
|
|
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
|
|
|
|
2021-09-17 18:29:46 +03:00
|
|
|
import aiosqlite
|
2021-11-08 18:57:31 +03:00
|
|
|
from chia.daemon.keychain_proxy import KeychainProxyConnectionFailure
|
2021-10-13 21:18:00 +03:00
|
|
|
from chia.data_layer.data_layer_wallet import DataLayerWallet
|
2021-09-16 04:31:41 +03:00
|
|
|
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
|
2021-09-17 18:29:46 +03:00
|
|
|
from chia.util.path import mkdir, path_from_root
|
2021-11-08 18:57:31 +03:00
|
|
|
from chia.wallet.wallet_node import WalletNode
|
2021-09-17 15:03:48 +03:00
|
|
|
|
2021-09-16 04:31:41 +03:00
|
|
|
|
|
|
|
class DataLayer:
|
|
|
|
data_store: DataStore
|
2021-09-17 17:30:14 +03:00
|
|
|
db_wrapper: DBWrapper
|
2021-09-17 18:29:46 +03:00
|
|
|
db_path: Path
|
|
|
|
connection: aiosqlite.Connection
|
2021-10-04 01:20:18 +03:00
|
|
|
config: Dict[str, Any]
|
2021-09-16 04:31:41 +03:00
|
|
|
log: logging.Logger
|
2021-10-13 21:18:00 +03:00
|
|
|
wallet: DataLayerWallet
|
2021-11-08 18:57:31 +03:00
|
|
|
wallet_node: Optional[WalletNode]
|
2021-10-04 01:20:18 +03:00
|
|
|
state_changed_callback: Optional[Callable[..., object]]
|
2021-09-16 04:31:41 +03:00
|
|
|
initialized: bool
|
2021-09-17 15:03:48 +03:00
|
|
|
|
2021-09-16 04:31:41 +03:00
|
|
|
def __init__(
|
|
|
|
self,
|
2021-09-17 17:30:14 +03:00
|
|
|
root_path: Path,
|
2021-11-08 18:57:31 +03:00
|
|
|
wallet_node: WalletNode,
|
2021-09-21 19:05:45 +03:00
|
|
|
name: Optional[str] = None,
|
2021-09-16 04:31:41 +03:00
|
|
|
):
|
2021-09-21 19:05:45 +03:00
|
|
|
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")
|
2021-09-16 04:31:41 +03:00
|
|
|
self.initialized = False
|
2021-10-04 00:35:44 +03:00
|
|
|
self.config = config
|
2021-11-08 18:57:31 +03:00
|
|
|
self.wallet_node = wallet_node
|
2021-09-21 19:05:45 +03:00
|
|
|
self.log = logging.getLogger(name if name is None else __name__)
|
2021-09-17 18:29:46 +03:00
|
|
|
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
|
|
|
|
2021-11-08 18:57:31 +03:00
|
|
|
async def _start(self) -> bool:
|
2021-10-04 00:35:44 +03:00
|
|
|
# create the store (db) and data store instance
|
2021-11-08 18:57:31 +03:00
|
|
|
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
|
2021-09-17 18:29:46 +03:00
|
|
|
self.connection = await aiosqlite.connect(self.db_path)
|
2021-09-17 17:30:14 +03:00
|
|
|
self.db_wrapper = DBWrapper(self.connection)
|
2021-09-16 04:31:41 +03:00
|
|
|
self.data_store = await DataStore.create(self.db_wrapper)
|
2021-11-08 18:57:31 +03:00
|
|
|
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(
|
2021-11-08 18:57:31 +03:00
|
|
|
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
|
2021-11-08 18:57:31 +03:00
|
|
|
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:
|
2021-11-08 18:57:31 +03:00
|
|
|
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)
|
2021-11-08 18:57:31 +03:00
|
|
|
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":
|
2021-10-24 16:38:04 +03:00
|
|
|
key = change["key"]
|
|
|
|
value = change["value"]
|
|
|
|
reference_node_hash = change.get("reference_node_hash")
|
|
|
|
side = change.get("side")
|
2021-10-20 16:00:26 +03:00
|
|
|
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"
|
2021-10-24 16:38:04 +03:00
|
|
|
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
|