Add docstrings for core classes and methods (#611)

This commit is contained in:
Jonathan Zernik 2021-01-11 19:43:33 -08:00 committed by GitHub
parent 37f56696ed
commit f9a02b2245
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 135 additions and 50 deletions

View file

@ -2,7 +2,9 @@ from typing import NamedTuple
class BuyOffer(NamedTuple):
"""Class for representing a generated offer on a seller node."""
"""Represents the offer details that are sent from seller
to buyer.
"""
squeak_hash: bytes
nonce: bytes
payment_request: str

View file

@ -3,7 +3,7 @@ from typing import Optional
class ReceivedOffer(NamedTuple):
"""Class for saving an offer from a remote peer."""
"""Represents an offer received by a buyer."""
received_offer_id: Optional[int]
squeak_hash: bytes
price_msat: int

View file

@ -4,6 +4,7 @@ from typing import Optional
class ReceivedPayment(NamedTuple):
"""Represents an payment received by a seller."""
received_payment_id: Optional[int]
created: Optional[datetime]
squeak_hash: bytes

View file

@ -3,6 +3,7 @@ from typing import Optional
class SentOffer(NamedTuple):
"""Represents an offer generated by a seller to be sent."""
sent_offer_id: Optional[int]
squeak_hash: bytes
payment_hash: bytes

View file

@ -4,6 +4,7 @@ from typing import Optional
class SentPayment(NamedTuple):
"""Represents a payment made by a buyer."""
sent_payment_id: Optional[int]
created: Optional[datetime]
peer_id: int

View file

@ -74,7 +74,7 @@ class SqueakController:
def get_buy_offer(self, squeak_hash: bytes, client_addr: str):
# Check if there is an existing offer for the hash/client_addr combination
sent_offer = self.get_saved_sent_offer(squeak_hash, client_addr)
return self.squeak_core.create_buy_offer(
return self.squeak_core.package_offer(
sent_offer,
self.config.lnd.external_host,
self.config.lnd.port,
@ -298,7 +298,7 @@ class SqueakController:
return self.config.core.network
def get_offer(self, squeak: CSqueak, offer_msg: squeak_server_pb2.SqueakBuyOffer, peer: SqueakPeer) -> ReceivedOffer:
return self.squeak_core.get_offer(squeak, offer_msg, peer)
return self.squeak_core.unpack_offer(squeak, offer_msg, peer)
def get_squeak_entry_with_profile(self, squeak_hash: bytes):
return self.squeak_db.get_squeak_entry_with_profile(squeak_hash)

View file

@ -37,6 +37,19 @@ class SqueakCore:
self.lightning_client = lightning_client
def make_squeak(self, signing_profile: SqueakProfile, content_str: str, replyto_hash: Optional[bytes] = None) -> SqueakEntry:
"""Create a new squeak.
Args:
signing_profile: The profile of the author of the squeak.
content_str: The content of the squeak as a string.
replyto_hash: The hash of the squeak to which this one is replying.
Returns:
SqueakEntry: containing the squeak together with its block header.
Raises:
Exception: If the profile does not have a signing key.
"""
if signing_profile.private_key is None:
raise Exception("Can't make squeak with a contact profile.")
signing_key_str = signing_profile.private_key.decode()
@ -59,6 +72,18 @@ class SqueakCore:
)
def validate_squeak(self, squeak: CSqueak) -> SqueakEntry:
"""Checks if the embedded block hash in the squeak is valid for its
block height.
Args:
squeak: The squeak to be validated.
Returns:
SqueakEntry: containing the squeak together with its block header.
Raises:
Exception: If the block hash is not valid.
"""
block_info = self.blockchain_client.get_block_info_by_height(
squeak.nBlockHeight)
if squeak.hashBlock != block_info.block_hash:
@ -69,10 +94,25 @@ class SqueakCore:
)
def get_best_block_height(self) -> int:
"""Get the current height of the latest block in the blockchain.
Returns:
int: the current latest block height.
"""
block_info = self.blockchain_client.get_best_block_info()
return block_info.block_height
def create_offer(self, squeak: CSqueak, client_addr: str, price_msat: int) -> SentOffer:
"""Creates an offer to sell a squeak key to another node.
Args:
squeak: The squeak to be sold.
client_addr: The IP address of the buyer.
price_msat: The price in msats.
Returns:
SentOffer: A record of the details of the offer for the seller.
"""
# Get the squeak hash
squeak_hash = get_hash(squeak)
# Generate a new random nonce
@ -108,7 +148,18 @@ class SqueakCore:
client_addr=client_addr,
)
def create_buy_offer(self, sent_offer: SentOffer, lnd_external_host: str, lnd_port: int) -> BuyOffer:
def package_offer(self, sent_offer: SentOffer, lnd_external_host: str, lnd_port: int) -> BuyOffer:
"""Package the offer details into a message that will be sent from
seller to buyer.
Args:
sent_offer: The offer that was already generated by the seller.
lnd_external_host: The host of the lnd node.
lnd_port: The port of the lnd node.
Returns:
SentOffer: A record of the details of the offer for the seller.
"""
return BuyOffer(
squeak_hash=sent_offer.squeak_hash,
nonce=sent_offer.nonce,
@ -117,53 +168,18 @@ class SqueakCore:
port=lnd_port,
)
def pay_offer(self, received_offer: ReceivedOffer) -> SentPayment:
if received_offer.received_offer_id is None:
raise Exception("Received offer must have a non-null offer_id.")
# Pay the invoice
payment = self.lightning_client.pay_invoice_sync(
received_offer.payment_request)
preimage = payment.payment_preimage
if not preimage:
raise Exception(
"Payment failed with error: {}".format(payment.payment_error)
)
# Calculate the secret key
nonce = received_offer.nonce
# secret_key = bxor(nonce, preimage)
secret_key = subtract_tweak(preimage, nonce)
# Save the preimage of the sent payment
return SentPayment(
sent_payment_id=None,
created=None,
peer_id=received_offer.peer_id,
squeak_hash=received_offer.squeak_hash,
payment_hash=received_offer.payment_hash,
secret_key=secret_key,
price_msat=received_offer.price_msat,
node_pubkey=received_offer.destination,
)
def unpack_offer(self, squeak: CSqueak, offer: BuyOffer, peer: SqueakPeer) -> ReceivedOffer:
"""Get the offer details from the message that the buyer
receives from the seller.
def get_received_payments(self, get_sent_offer_fn, latest_settle_index) -> Iterator[ReceivedPayment]:
for invoice in self.lightning_client.subscribe_invoices(
settle_index=latest_settle_index,
):
if invoice.settled:
payment_hash = invoice.r_hash
settle_index = invoice.settle_index
sent_offer = get_sent_offer_fn(payment_hash)
received_payment = ReceivedPayment(
received_payment_id=None,
created=None,
squeak_hash=sent_offer.squeak_hash,
payment_hash=sent_offer.payment_hash,
price_msat=sent_offer.price_msat,
settle_index=settle_index,
client_addr=sent_offer.client_addr,
)
yield received_payment
Args:
squeak: The squeak that will be unlocked upon payment.
offer: The offer details received from the seller.
peer: The peer that sent the offer.
def get_offer(self, squeak: CSqueak, offer: BuyOffer, peer: SqueakPeer) -> ReceivedOffer:
Returns:
ReceivedOffer: A record of the details of the offer for the buyer.
"""
if peer.peer_id is None:
raise Exception("Peer must have a non-null peer_id.")
# Get the squeak hash
@ -212,3 +228,65 @@ class SqueakCore:
# )
# )
return decoded_offer
def pay_offer(self, received_offer: ReceivedOffer) -> SentPayment:
"""Pay the offer that the buyer received from the seller.
Args:
received_offer: The details of the offer received by the buyer.
Returns:
SentPayment: A record of the sent payment.
"""
# Pay the invoice
payment = self.lightning_client.pay_invoice_sync(
received_offer.payment_request)
preimage = payment.payment_preimage
if not preimage:
raise Exception(
"Payment failed with error: {}".format(payment.payment_error)
)
# Calculate the secret key
nonce = received_offer.nonce
# secret_key = bxor(nonce, preimage)
secret_key = subtract_tweak(preimage, nonce)
# Save the preimage of the sent payment
return SentPayment(
sent_payment_id=None,
created=None,
peer_id=received_offer.peer_id,
squeak_hash=received_offer.squeak_hash,
payment_hash=received_offer.payment_hash,
secret_key=secret_key,
price_msat=received_offer.price_msat,
node_pubkey=received_offer.destination,
)
def get_received_payments(self, get_sent_offer_fn, latest_settle_index) -> Iterator[ReceivedPayment]:
"""Get an iterator of received payments.
Args:
get_sent_offer_fn: Function that takes a payment hash and returns
the corresponding SentOffer.
latest_settle_index: The latest settle index of the lnd invoice database.
Returns:
Iterator[ReceivedPayment]: An iterator of received payments.
"""
for invoice in self.lightning_client.subscribe_invoices(
settle_index=latest_settle_index,
):
if invoice.settled:
payment_hash = invoice.r_hash
settle_index = invoice.settle_index
sent_offer = get_sent_offer_fn(payment_hash)
received_payment = ReceivedPayment(
received_payment_id=None,
created=None,
squeak_hash=sent_offer.squeak_hash,
payment_hash=sent_offer.payment_hash,
price_msat=sent_offer.price_msat,
settle_index=settle_index,
client_addr=sent_offer.client_addr,
)
yield received_payment

View file

@ -3,6 +3,7 @@ from typing import Optional
class SqueakPeer(NamedTuple):
"""Represents another node in the network."""
peer_id: Optional[int]
peer_name: str
host: str

View file

@ -3,6 +3,7 @@ from typing import Optional
class SqueakProfile(NamedTuple):
"""Represents a user who can author squeaks."""
profile_id: Optional[int]
profile_name: str
private_key: Optional[bytes]