mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-15 12:50:47 +02:00
Add docstrings for core classes and methods (#611)
This commit is contained in:
parent
37f56696ed
commit
f9a02b2245
9 changed files with 135 additions and 50 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue