diff --git a/squeaknode/core/squeak_core.py b/squeaknode/core/squeak_core.py index a2e788c3..52417cf6 100644 --- a/squeaknode/core/squeak_core.py +++ b/squeaknode/core/squeak_core.py @@ -151,7 +151,14 @@ class SqueakCore: block_info = self.bitcoin_client.get_best_block_info() return block_info.block_height - def create_offer(self, squeak: CSqueak, secret_key: bytes, peer_address: PeerAddress, price_msat: int) -> SentOffer: + 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: @@ -166,7 +173,8 @@ class SqueakCore: # Get the squeak hash squeak_hash = get_hash(squeak) # Generate a new random nonce - nonce = generate_tweak() + if nonce is None: + nonce = generate_tweak() # Calculate the preimage preimage = add_tweak(secret_key, nonce) # Create the lightning invoice diff --git a/tests/core/test_squeak_core.py b/tests/core/test_squeak_core.py index 8a3505bd..e60fa089 100644 --- a/tests/core/test_squeak_core.py +++ b/tests/core/test_squeak_core.py @@ -26,11 +26,16 @@ from squeaknode.bitcoin.block_info import BlockInfo from squeaknode.core.lightning_address import LightningAddressHostPort from squeaknode.core.peer_address import Network from squeaknode.core.peer_address import PeerAddress +from squeaknode.core.secret_keys import add_tweak +from squeaknode.core.secret_keys import generate_tweak from squeaknode.core.squeak_core import SqueakCore from squeaknode.core.squeaks import get_hash +from squeaknode.lightning.info import Info from squeaknode.lightning.invoice import Invoice from squeaknode.lightning.lightning_client import LightningClient -from tests.utils import gen_random_hash +from squeaknode.lightning.pay_req import PayReq +from squeaknode.lightning.payment import Payment +from tests.utils import sha256 @pytest.fixture @@ -44,15 +49,19 @@ def price_msat(): @pytest.fixture -def preimage(): - # TODO: This should be generated from the tweak of the decryption key. - yield gen_random_hash() +def nonce(): + yield generate_tweak() + + +@pytest.fixture +def preimage(secret_key, nonce): + yield add_tweak(secret_key, nonce) @pytest.fixture def payment_hash(preimage): - # TODO: This should be the hash of the preimage - yield gen_random_hash() + # TODO: When PTLC is used, this should be the payment point of preimage. + yield sha256(preimage) @pytest.fixture @@ -65,13 +74,38 @@ def creation_date(): yield 777777 +@pytest.fixture +def timestamp(): + yield 8888888 + + @pytest.fixture def expiry(): yield 5555 @pytest.fixture -def invoice(payment_hash, payment_request, price_msat, creation_date, expiry): +def seller_pubkey(): + yield "fake_seller_pubkey" + + +@pytest.fixture +def uris(): + yield [ + 'fake_pubkey@foobar.com:12345', + 'fake_pubkey@fakehost.com:56789', + ] + + +@pytest.fixture +def info(uris): + yield Info( + uris=uris, + ) + + +@pytest.fixture +def invoice(payment_request, price_msat, creation_date, expiry): yield Invoice( r_hash=payment_hash, payment_request=payment_request, @@ -83,6 +117,40 @@ def invoice(payment_hash, payment_request, price_msat, creation_date, expiry): ) +@pytest.fixture +def pay_req( + payment_hash, + price_msat, + payment_request, + seller_pubkey, + timestamp, + expiry, +): + yield PayReq( + payment_hash=payment_hash, + num_msat=price_msat, + destination=seller_pubkey, + timestamp=timestamp, + expiry=expiry, + ) + + +@pytest.fixture +def successful_payment(preimage): + yield Payment( + payment_preimage=preimage, + payment_error='', + ) + + +@pytest.fixture +def failed_payment(payment_request): + yield Payment( + payment_preimage=b'', + payment_error='Payment failed.', + ) + + class MockBitcoinClient(BitcoinClient): def __init__(self, best_block_info): @@ -112,20 +180,23 @@ class MockBitcoinClient(BitcoinClient): class MockLightningClient(LightningClient): - def __init__(self, invoice): + def __init__(self, info, invoice, pay_req, payment): + self.info = info self.invoice = invoice + self.pay_req = pay_req + self.payment = payment def get_info(self): - pass + return self.info def create_invoice(self, preimage: bytes, amount_msat: int): return self.invoice def decode_pay_req(self, payment_request: str): - pass + return self.pay_req def pay_invoice(self, payment_request: str): - pass + return self.payment def subscribe_invoices(self, settle_index: int): pass @@ -137,8 +208,8 @@ def bitcoin_client(genesis_block_info): @pytest.fixture -def lightning_client(invoice): - return MockLightningClient(invoice) +def lightning_client(info, invoice, pay_req, successful_payment): + return MockLightningClient(info, invoice, pay_req, successful_payment) @pytest.fixture @@ -146,24 +217,24 @@ def squeak_core(bitcoin_client, lightning_client): yield SqueakCore(bitcoin_client, lightning_client) -@pytest.fixture -def squeak_and_decryption_key(squeak_core, signing_profile, squeak_content): - yield squeak_core.make_squeak( - signing_profile, - squeak_content, - ) +# @pytest.fixture +# def squeak_and_decryption_key(squeak_core, signing_profile, squeak_content): +# yield squeak_core.make_squeak( +# signing_profile, +# squeak_content, +# ) -@pytest.fixture -def squeak(squeak_and_decryption_key): - squeak, _ = squeak_and_decryption_key - yield squeak +# @pytest.fixture +# def squeak(squeak_and_decryption_key): +# squeak, _ = squeak_and_decryption_key +# yield squeak -@pytest.fixture -def decryption_key(squeak_and_decryption_key): - _, decryption_key = squeak_and_decryption_key - yield decryption_key +# @pytest.fixture +# def decryption_key(squeak_and_decryption_key): +# _, decryption_key = squeak_and_decryption_key +# yield decryption_key @pytest.fixture @@ -175,6 +246,56 @@ def peer_address(): ) +@pytest.fixture +def seller_peer_address(): + yield PeerAddress( + network=Network.IPV4, + host="fake_seller_host", + port=4321, + ) + + +@pytest.fixture +def created_offer(squeak_core, squeak, secret_key, peer_address, price_msat, nonce): + yield squeak_core.create_offer( + squeak, + secret_key, + peer_address, + price_msat, + nonce, + ) + + +@pytest.fixture +def packaged_offer(squeak_core, created_offer): + yield squeak_core.package_offer(created_offer, None) + + +@pytest.fixture +def unpacked_offer(squeak_core, squeak, packaged_offer, seller_peer_address): + yield squeak_core.unpack_offer(squeak, packaged_offer, seller_peer_address) + + +@pytest.fixture +def sent_payment(squeak_core, unpacked_offer): + yield squeak_core.pay_offer(unpacked_offer) + + +def test_make_squeak( + squeak_core, + signing_profile, + squeak_content, +): + created_squeak, created_secret_key = squeak_core.make_squeak( + signing_profile, squeak_content) + decrypted_created_content = squeak_core.get_decrypted_content( + created_squeak, + created_secret_key, + ) + + assert decrypted_created_content == squeak_content + + def test_get_block_header( squeak_core, squeak, @@ -185,13 +306,8 @@ def test_get_block_header( assert block_header == genesis_block_info.block_header -def test_get_decrypted_content(squeak_core, squeak, decryption_key, squeak_content): - decrypted_content = squeak_core.get_decrypted_content( - squeak, - decryption_key, - ) - - assert decrypted_content == squeak_content +def test_check_squeak(squeak_core, squeak): + squeak_core.check_squeak(squeak) def test_get_best_block_height(squeak_core, genesis_block_info): @@ -200,19 +316,37 @@ def test_get_best_block_height(squeak_core, genesis_block_info): assert best_block_height == genesis_block_info.block_height -def test_create_offer(squeak_core, squeak, decryption_key, peer_address, price_msat, invoice): - created_sent_offer = squeak_core.create_offer( +def test_create_offer(squeak, peer_address, price_msat, created_offer, invoice): + + assert created_offer.squeak_hash == get_hash(squeak) + assert created_offer.payment_hash == invoice.r_hash + # assert created_offer.secret_key == secret_key + assert created_offer.price_msat == price_msat + assert created_offer.payment_request == invoice.payment_request + assert created_offer.invoice_time == invoice.creation_date + assert created_offer.invoice_expiry == invoice.expiry + assert created_offer.peer_address == peer_address + + +def test_packaged_offer(squeak, packaged_offer): + + assert packaged_offer is not None + + +def test_unpacked_offer(unpacked_offer): + + assert unpacked_offer is not None + + +def test_sent_payment(sent_payment): + + assert sent_payment is not None + + +def test_unlock_squeak(squeak_core, squeak, squeak_content, sent_payment): + decrypted_content = squeak_core.get_decrypted_content( squeak, - decryption_key, - peer_address, - price_msat, + sent_payment.secret_key, ) - assert created_sent_offer.squeak_hash == get_hash(squeak) - assert created_sent_offer.payment_hash == invoice.r_hash - # assert created_sent_offer.secret_key == decryption_key - assert created_sent_offer.price_msat == price_msat - assert created_sent_offer.payment_request == invoice.payment_request - assert created_sent_offer.invoice_time == invoice.creation_date - assert created_sent_offer.invoice_expiry == invoice.expiry - assert created_sent_offer.peer_address == peer_address + assert decrypted_content == squeak_content diff --git a/tests/utils.py b/tests/utils.py index ca610394..0818a420 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -19,6 +19,7 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import hashlib import os import uuid @@ -40,6 +41,10 @@ def gen_random_hash(): return os.urandom(HASH_LENGTH) +def sha256(data): + return hashlib.sha256(data).digest() + + def address_from_signing_key(signing_key): verifying_key = signing_key.get_verifying_key() return CSqueakAddress.from_verifying_key(verifying_key)