Use blockchain client to get subscription (#205)

* Use blockchain client in subscription class

* Refactor bitcoin blockchain client

* Use blockchain client instead of lightning client in squeak maker
This commit is contained in:
Jonathan Zernik 2020-08-02 02:21:28 -07:00 committed by GitHub
parent 9db19bcb46
commit ad0632bd1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 116 additions and 41 deletions

View file

@ -4,18 +4,46 @@ from typing import Optional
import requests
from squeakserver.blockchain.block_info import BlockInfo
from squeakserver.blockchain.blockchain_client import BlockchainClient
logger = logging.getLogger(__name__)
class BitcoinBlockchainClient:
class BitcoinBlockchainClient(BlockchainClient):
"""Access a bitcoin daemon using RPC."""
def __init__(self, host: str, port: int, rpc_user: str, rpc_password: str,) -> None:
self.url = f"https://{rpc_user}:{rpc_password}@{host}:{port}"
self.headers = {"content-type": "application/json"}
def get_block_hash(self, block_height: int) -> Optional[bytes]:
# return self.access.getblockhash(block_height)
def get_best_block_info(self) -> BlockInfo:
block_height = self.get_block_count() - 1
return self.get_block_info_by_height(block_height)
def get_block_info_by_height(self, block_height: int) -> BlockInfo:
block_hash = self.get_block_hash(block_height)
block_header = self.get_block_header(block_hash, False)
return BlockInfo(block_height, block_hash, block_header)
def get_block_count(self) -> Optional[int]:
payload = {
"method": "getblockcount",
"params": [],
"jsonrpc": "2.0",
"id": 0,
}
response = requests.post(
self.url, data=json.dumps(payload), headers=self.headers,
).json()
logger.info("Got response for get_block_count: {}".format(response))
result = response["result"]
block_count = int(result)
logger.info("Got block_count: {}".format(block_count))
return block_count
def get_block_hash(self, block_height: int) -> Optional[str]:
payload = {
"method": "getblockhash",
"params": [block_height],
@ -26,11 +54,28 @@ class BitcoinBlockchainClient:
self.url, data=json.dumps(payload), headers=self.headers,
).json()
logger.info("Got response for get_block_hash: {}".format(response))
result = response["result"]
block_hash = bytes.fromhex(result)
block_hash = result
logger.info("Got block_hash: {}".format(block_hash))
return block_hash
def get_block_header(self, block_hash: int, verbose: bool) -> Optional[bytes]:
# def get_best_block_hash(self) -> Optional[bytes]:
# payload = {
# "method": "getblockhash",
# "params": [],
# "jsonrpc": "2.0",
# "id": 0,
# }
# response = requests.post(
# self.url, data=json.dumps(payload), headers=self.headers,
# ).json()
# result = response["result"]
# block_hash = bytes.fromhex(result)
# return block_hash
def get_block_header(self, block_hash: str, verbose: bool) -> Optional[bytes]:
payload = {
"method": "getblockheader",
"params": [block_hash, verbose],
@ -41,6 +86,7 @@ class BitcoinBlockchainClient:
self.url, data=json.dumps(payload), headers=self.headers,
).json()
logger.info("Got header request result: {}".format(response))
logger.info("Got response for get_block_header: {}".format(response))
result = response["result"]
logger.info("Got block_header: {}".format(result))
return result

View file

@ -0,0 +1,6 @@
from collections import namedtuple
BlockInfo = namedtuple(
"BlockInfo",
"block_height, block_hash, block_header",
)

View file

@ -0,0 +1,22 @@
import json
import logging
from typing import Optional
from abc import ABC, abstractmethod
from squeakserver.blockchain.block_info import BlockInfo
import requests
logger = logging.getLogger(__name__)
class BlockchainClient(ABC):
@abstractmethod
def get_best_block_info(self) -> BlockInfo:
pass
@abstractmethod
def get_block_info_by_height(self) -> BlockInfo:
pass

View file

@ -13,13 +13,16 @@ class SqueakBlockVerifier:
def verify_squeak_block(self, squeak_hash):
logger.info("Verifying squeak hash: {}".format(squeak_hash))
squeak = self._get_squeak(squeak_hash)
valid_block_info = self._check_block_info(squeak)
logger.info("Is block hash correct: {}".format(valid_block_info))
if valid_block_info:
block_header = self._get_block_header(squeak)
self._mark_squeak_verified(squeak_hash, block_header)
block_info = self._get_block_info_for_height(squeak.nBlockHeight)
logger.info("Checking block height: {}".format(squeak.nBlockHeight))
logger.info("Checking block hash: {}".format(squeak.hashBlock.hex()))
if squeak.hashBlock.hex() == block_info.block_hash:
logger.info("block hash correct: {}".format(block_info))
self._mark_squeak_verified(squeak_hash, block_info)
else:
self._delete_squeak
logger.info("block hash incorrect: {}".format(block_info))
self._delete_squeak(squeak_hash)
def verify_all_unverified_squeaks(self):
logger.info("Calling verify_squeaks.")
@ -42,24 +45,12 @@ class SqueakBlockVerifier:
squeak_entry = self.postgres_db.get_squeak_entry(squeak_hash)
return squeak_entry.squeak
def _mark_squeak_verified(self, squeak_hash, block_header):
self.postgres_db.mark_squeak_block_valid(squeak_hash, block_header)
def _mark_squeak_verified(self, squeak_hash, block_info):
block_header_bytes = bytes.fromhex(block_info.block_header)
self.postgres_db.mark_squeak_block_valid(squeak_hash, block_header_bytes)
def _delete_squeak(self, squeak_hash):
self.postgres_db.delete_squeak(squeak_hash)
def _check_block_info(self, squeak):
block_height = squeak.nBlockHeight
block_hash = self._get_block_hash(block_height)
return squeak.hashBlock == block_hash
def _get_block_header(self, squeak):
block_hash_str = squeak.hashBlock.hex()
block_header = self.blockchain_client.get_block_header(block_hash_str, False)
logger.info("Got block header from blockchain: {}".format(block_header))
return bytes.fromhex(block_header)
def _get_block_hash(self, block_height):
block_hash = self.blockchain_client.get_block_hash(block_height)
logger.info("Got block hash from blockchain: {}".format(block_hash))
return block_hash
def _get_block_info_for_height(self, block_height):
return self.blockchain_client.get_block_info_by_height(block_height)

View file

@ -10,17 +10,17 @@ logger = logging.getLogger(__name__)
class SqueakMaker:
def __init__(self, lightning_client):
self.lightning_client = lightning_client
def __init__(self, blockchain_client):
self.blockchain_client = blockchain_client
def make_squeak(self, signing_profile, content_str, replyto_hash=None):
signing_key_str = signing_profile.private_key.decode()
signing_key = CSigningKey(signing_key_str)
logger.info("Creating squeak with signing key: {}".format(signing_key))
logger.info("Creating squeak with replyto_hash: {}".format(replyto_hash))
latest_block = self._get_latest_block()
block_height = latest_block.block_height
block_hash = latest_block.block_hash
block_info = self._get_latest_block_info()
block_height = block_info.block_height
block_hash = bytes.fromhex(block_info.block_hash)
timestamp = self._get_current_time_s()
logger.info("Creating squeak with block height: {}".format(block_height))
logger.info("Creating squeak with block hash: {}".format(block_hash))
@ -38,11 +38,14 @@ class SqueakMaker:
replyto_hash,
)
def _get_latest_block(self):
get_info_response = self.lightning_client.get_info()
block_hash = bytes.fromhex(get_info_response.block_hash)
block_height = get_info_response.block_height
return BlockInfo(block_hash, block_height)
# def _get_latest_block(self):
# get_info_response = self.lightning_client.get_info()
# block_hash = bytes.fromhex(get_info_response.block_hash)
# block_height = get_info_response.block_height
# return BlockInfo(block_hash, block_height)
def _get_latest_block_info(self):
return self.blockchain_client.get_best_block_info()
def _get_current_time_s(self):
return int(time.time())

View file

@ -57,6 +57,7 @@ class SqueakNode:
self.squeak_subscription_downloader = SqueakSubscriptionDownloader(
postgres_db,
self.squeak_store,
self.blockchain_client,
)
def start_running(self):
@ -173,7 +174,7 @@ class SqueakNode:
def make_squeak(self, profile_id, content_str, replyto_hash):
squeak_profile = self.postgres_db.get_profile(profile_id)
squeak_maker = SqueakMaker(self.lightning_client)
squeak_maker = SqueakMaker(self.blockchain_client)
squeak = squeak_maker.make_squeak(squeak_profile, content_str, replyto_hash)
return self.save_created_squeak(squeak)

View file

@ -9,9 +9,15 @@ SUBSCRIBE_UPDATE_INTERVAL_S = 10.0
class SqueakSubscriptionDownloader:
def __init__(self, postgres_db, squeak_store, update_interval_s=SUBSCRIBE_UPDATE_INTERVAL_S):
def __init__(self,
postgres_db,
squeak_store,
blockchain_client,
update_interval_s=SUBSCRIBE_UPDATE_INTERVAL_S,
):
self.postgres_db = postgres_db
self.squeak_store = squeak_store
self.blockchain_client = blockchain_client
self.update_interval_s = update_interval_s
def sync_subscriptions(self):