def forward_secret_key(self, squeak): logger.debug("Forward new secret key for hash: {!r}".format( get_hash(squeak).hex(), )) for peer in self.network_manager.get_connected_peers(): if peer.is_remote_subscribed(squeak): logger.debug("Forwarding to peer: {}".format(peer, )) squeak_hash = get_hash(squeak) inv = CInv(type=MSG_SECRET_KEY, hash=squeak_hash) inv_msg = msg_inv(inv=[inv]) peer.send_msg(inv_msg) logger.debug("Finished checking peers to forward.")
def get_offer_reply(self, squeak: CSqueak, peer_address: PeerAddress, price_msat: int) -> Optional[OfferReply]: sent_offer = self.get_sent_offer_for_peer( squeak, peer_address, price_msat, ) if sent_offer is None: return None lnd_external_address: Optional[LightningAddressHostPort] = None if self.config.lnd.external_host: lnd_external_address = LightningAddressHostPort( host=self.config.lnd.external_host, port=self.config.lnd.port, ) try: offer = self.squeak_core.package_offer( sent_offer, lnd_external_address, ) return OfferReply( squeak_hash=get_hash(squeak), offer=offer, ) except Exception: return None
def get_sent_offer_for_peer(self, squeak: CSqueak, peer_address: PeerAddress, price_msat: int) -> Optional[SentOffer]: squeak_hash = get_hash(squeak) # Check if there is an existing offer for the hash/peer_address combination sent_offer = self.squeak_db.get_sent_offer_by_squeak_hash_and_peer( squeak_hash, peer_address, ) if sent_offer: return sent_offer secret_key = self.get_squeak_secret_key(squeak_hash) if squeak is None or secret_key is None: return None try: sent_offer = self.squeak_core.create_offer( squeak, secret_key, peer_address, price_msat, ) except Exception: logger.exception("Failed to create offer.") return None self.squeak_db.insert_sent_offer(sent_offer) return sent_offer
def download_squeak( self, squeak_hash: bytes, min_block: Optional[int] = None, max_block: Optional[int] = None, pubkeys: Optional[List[SqueakPublicKey]] = None, ) -> None: # Download the squeak if not already owned. if self.squeak_store.get_squeak(squeak_hash): raise Exception('Squeak already saved.') # Download the squeak if not already owned. squeak = self.client.get_squeak(squeak_hash) # Check if the squeak is valid. if not squeak: raise Exception('Squeak not found.') if get_hash(squeak) != squeak_hash: raise Exception('Squeak has wrong hash.') if min_block and squeak.nBlockHeight < min_block: raise Exception('Squeak has block height below minimum.') if max_block and squeak.nBlockHeight > max_block: raise Exception('Squeak has block height above minimum.') if pubkeys and squeak.GetPubKey() not in pubkeys: raise Exception('Squeak has wronge pubkey.') # Save the squeak. self.squeak_store.save_squeak(squeak)
def handle_new_squeaks(self): logger.debug("Starting UpdateSubscribedSqueaksWorker...") for squeak in self.squeak_controller.subscribe_new_squeaks( self.stopped, ): logger.debug("Handling new squeak: {!r}".format( get_hash(squeak).hex(), )) # self.forward_squeak(squeak) self.squeak_controller.forward_squeak(squeak)
def unpack_offer( self, squeak: CSqueak, offer: Offer, peer_address: PeerAddress, check_payment_point: bool = False, ) -> ReceivedOffer: """Get the offer details from the message that the buyer receives from the seller. 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. Returns: ReceivedOffer: A record of the details of the offer for the buyer. """ # Get the squeak hash squeak_hash = get_hash(squeak) # Check if squeak hash matches squeak_hash in buy_offer. if squeak_hash != offer.squeak_hash: raise Exception( "Squeak hash in offer {!r} does not match squeak hash {!r}.". format(offer.squeak_hash, squeak_hash)) # Decode the payment request pay_req = self.lightning_client.decode_pay_req(offer.payment_request) squeak_payment_point = squeak.paymentPoint payment_hash = pay_req.payment_hash price_msat = pay_req.num_msat destination = pay_req.destination invoice_timestamp = pay_req.timestamp invoice_expiry = pay_req.expiry lightning_address = LightningAddressHostPort( host=offer.host or peer_address.host, port=offer.port, ) payment_point = pay_req.payment_point expected_payment_point = squeak.paymentPoint if check_payment_point: if payment_point != expected_payment_point: raise Exception("Invalid payment point.") return ReceivedOffer( received_offer_id=None, squeak_hash=squeak_hash, price_msat=price_msat, payment_hash=payment_hash, nonce=offer.nonce, payment_point=squeak_payment_point, invoice_timestamp=invoice_timestamp, invoice_expiry=invoice_expiry, payment_request=offer.payment_request, destination=destination, lightning_address=lightning_address, peer_address=peer_address, paid=False, )
def create_offer( self, squeak: CSqueak, secret_key: bytes, peer_address: PeerAddress, price_msat: int, nonce: bytes = None, ) -> SentOffer: """Creates an offer to sell a squeak key to another node. Args: squeak: The squeak to be sold. secret_key: The secret key to the squeak. peer_address: The 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 if nonce is None: nonce = generate_tweak() # Calculate the preimage preimage = add_tweak(secret_key, nonce) # Create the lightning invoice invoice = self.lightning_client.create_invoice(preimage, price_msat) return SentOffer( sent_offer_id=None, squeak_hash=squeak_hash, payment_hash=invoice.r_hash, nonce=nonce, price_msat=price_msat, payment_request=invoice.payment_request, invoice_time=invoice.creation_date, invoice_expiry=invoice.expiry, peer_address=peer_address, paid=False, )
def subscribe_squeak_entries(self, stopped: threading.Event): for item in self.new_squeak_listener.yield_items(stopped): squeak_hash = get_hash(item) yield self.get_squeak_entry(squeak_hash)
def subscribe_timeline_squeak_entries(self, stopped: threading.Event): for item in self.new_squeak_listener.yield_items(stopped): followed_addresses = self.get_followed_addresses() if str(item.GetAddress()) in set(followed_addresses): squeak_hash = get_hash(item) yield self.get_squeak_entry(squeak_hash)
def subscribe_squeak_address_entries(self, squeak_address: str, stopped: threading.Event): for item in self.new_squeak_listener.yield_items(stopped): if squeak_address == str(item.GetAddress()): squeak_hash = get_hash(item) yield self.get_squeak_entry(squeak_hash)
def subscribe_squeak_ancestor_entries(self, squeak_hash: bytes, stopped: threading.Event): for item in self.new_squeak_listener.yield_items(stopped): if squeak_hash == get_hash(item): yield self.get_ancestor_squeak_entries(squeak_hash)
def squeak_hash(squeak): yield get_hash(squeak)
def subscribe_squeak_reply_entries(self, squeak_hash: bytes, stopped: threading.Event): for item in self.new_squeak_listener.yield_items(stopped): if squeak_hash == item.hashReplySqk: reply_hash = get_hash(item) yield self.get_squeak_entry(reply_hash)
def reply_squeak_hash(reply_squeak): yield get_hash(reply_squeak)
def subscribe_squeak_public_key_entries(self, public_key: SqueakPublicKey, stopped: threading.Event): for item in self.squeak_store.subscribe_new_squeaks(stopped): if public_key == item.GetPubKey(): squeak_hash = get_hash(item) yield self.get_squeak_entry(squeak_hash)
def subscribe_squeak_entries(self, stopped: threading.Event): for item in self.squeak_store.subscribe_new_squeaks(stopped): squeak_hash = get_hash(item) yield self.get_squeak_entry(squeak_hash)
def subscribe_timeline_squeak_entries(self, stopped: threading.Event): for item in self.squeak_store.subscribe_new_squeaks(stopped): followed_public_keys = self.squeak_store.get_followed_public_keys() if item.GetPubKey() in set(followed_public_keys): squeak_hash = get_hash(item) yield self.get_squeak_entry(squeak_hash)
def test_get_hash(squeak, squeak_hash): expected_hash = squeak.GetHash()[::-1] assert get_hash(squeak) == expected_hash
def matches_requested_squeak_hash(self, squeak_hash: bytes) -> bool: return squeak_hash == get_hash(self.squeak)
def resqueak_hash(resqueak): yield get_hash(resqueak)