Update squeaklib to support private messages (#1897)

* Update squeaklib and update import from keys module

* Rename signing key variable to private key in test util

* Fix calling make squeak function

* Update db data file to v3

* Add recipient public key column to squeak table

* Got squeak entry db query working with alias for profiles table

* Add test for make squeak with recipient

* Add test case for get profile from squeak entry query

* Got outer join with recipient profile working

* Use outer join to get recipient profile for all squeak entry db queries
This commit is contained in:
Jonathan Zernik 2021-12-27 00:56:31 -08:00 committed by GitHub
parent 1a159a5f10
commit 51f412d75f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 357 additions and 85 deletions

View file

@ -30,8 +30,8 @@ from contextlib import contextmanager
from squeak.core.elliptic import scalar_difference
from squeak.core.elliptic import scalar_from_bytes
from squeak.core.elliptic import scalar_to_bytes
from squeak.core.signing import SqueakPrivateKey
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
from proto import lnd_pb2
from proto import squeak_admin_pb2

View file

@ -3,4 +3,4 @@ grpcio==1.39.0
grpcio-tools==1.39.0
importlib_resources==1.4.0
pytest==6.2.5
squeaklib==0.9.1
squeaklib==0.10.2

View file

@ -14,5 +14,5 @@ python-bitcoinlib==0.11.0
pyzmq==22.3.0
requests==2.26.0
SQLAlchemy==1.4.25
squeaklib==0.9.1
squeaklib==0.10.2
typed-config==0.2.5

View file

@ -22,7 +22,7 @@
import logging
from typing import Optional
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPublicKey
from proto import squeak_admin_pb2
from squeaknode.admin.profile_image_util import bytes_to_base64_string
@ -218,6 +218,7 @@ def message_to_squeak_entry(msg: squeak_admin_pb2.SqueakDisplayEntry) -> SqueakE
public_key=SqueakPublicKey.from_bytes(
bytes.fromhex(msg.author_pubkey),
),
recipient_public_key=None, # TODO: maybe implement this.
block_height=msg.block_height,
block_hash=bytes.fromhex(msg.block_hash),
block_time=msg.block_time,
@ -226,6 +227,7 @@ def message_to_squeak_entry(msg: squeak_admin_pb2.SqueakDisplayEntry) -> SqueakE
is_unlocked=msg.is_unlocked,
secret_key=secret_key,
squeak_profile=None, # TODO: message to squeak profile
recipient_squeak_profile=None, # TODO: message to squeak profile
liked_time_ms=like_time_ms,
content=content_str,
)

View file

@ -21,8 +21,8 @@
# SOFTWARE.
import logging
from squeak.core.signing import SqueakPrivateKey
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
from proto import squeak_admin_pb2
from squeaknode.admin.messages import connected_peer_to_message

View file

@ -21,8 +21,8 @@
# SOFTWARE.
from typing import Optional
from squeak.core.signing import SqueakPrivateKey
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
from squeaknode.core.squeak_profile import SqueakProfile

View file

@ -22,7 +22,7 @@
from typing import NamedTuple
from typing import Optional
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPublicKey
from squeaknode.core.squeak_profile import SqueakProfile
@ -31,6 +31,7 @@ class SqueakEntry(NamedTuple):
squeak_hash: bytes
serialized_squeak: bytes
public_key: SqueakPublicKey
recipient_public_key: Optional[SqueakPublicKey]
block_height: int
block_hash: bytes
block_time: int
@ -39,5 +40,6 @@ class SqueakEntry(NamedTuple):
is_unlocked: bool
secret_key: Optional[bytes]
squeak_profile: Optional[SqueakProfile]
recipient_squeak_profile: Optional[SqueakProfile]
liked_time_ms: Optional[int] = None
content: Optional[str] = None

View file

@ -22,8 +22,8 @@
from typing import NamedTuple
from typing import Optional
from squeak.core.signing import SqueakPrivateKey
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
class SqueakProfile(NamedTuple):

View file

@ -27,7 +27,8 @@ from squeak.core import CheckSqueak
from squeak.core import CSqueak
from squeak.core import MakeSqueakFromStr
from squeak.core.elliptic import payment_point_bytes_from_scalar_bytes
from squeak.core.signing import SqueakPrivateKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
DATA_KEY_LENGTH = 32
@ -58,6 +59,7 @@ def make_squeak_with_block(
block_height: int,
block_hash: bytes,
replyto_hash: Optional[bytes] = None,
recipient_public_key: Optional[SqueakPublicKey] = None,
) -> Tuple[CSqueak, bytes]:
"""Create a new squeak.
@ -79,7 +81,8 @@ def make_squeak_with_block(
block_height,
block_hash,
timestamp,
replyto_hash,
reply_to=replyto_hash,
recipient=recipient_public_key,
)

View file

@ -37,7 +37,7 @@ version_locations = %(here)s/alembic/versions
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = sqlite://///home/yzernik/.sqk/data/testnet/data-v2.db
sqlalchemy.url = sqlite://///home/yzernik/.sqk/data/testnet/data-v3.db
[post_write_hooks]

View file

@ -0,0 +1,51 @@
# MIT License
#
# Copyright (c) 2020 Jonathan Zernik
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# 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.
"""Add recipient public key column to squeaks table.
Revision ID: c0760e8ce4ba
Revises: b78f8169d063
Create Date: 2021-12-26 14:13:00.159229
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = 'c0760e8ce4ba'
down_revision = 'b78f8169d063'
branch_labels = None
depends_on = None
def upgrade():
with op.batch_alter_table('squeak', schema=None) as batch_op:
batch_op.add_column(sa.Column('recipient_public_key',
sa.LargeBinary(length=33), nullable=True))
batch_op.create_index(batch_op.f('ix_squeak_recipient_public_key'), [
'recipient_public_key'], unique=False)
def downgrade():
with op.batch_alter_table('squeak', schema=None) as batch_op:
batch_op.drop_index(batch_op.f('ix_squeak_recipient_public_key'))
batch_op.drop_column('recipient_public_key')

View file

@ -24,6 +24,9 @@ from pathlib import Path
from sqlalchemy import create_engine
DB_FILE = "data-v3.db"
def get_engine(connection_string):
return create_engine(connection_string)
@ -31,8 +34,9 @@ def get_engine(connection_string):
def get_sqlite_connection_string(sqk_dir, network):
data_dir = Path(sqk_dir).joinpath("data").joinpath(network)
data_dir.mkdir(parents=True, exist_ok=True)
return "sqlite:////{}/data-v2.db".format(
return "sqlite:////{}/{}".format(
data_dir,
DB_FILE,
)

View file

@ -76,6 +76,8 @@ class Models:
Column("time_s", Integer, nullable=False),
Column("author_public_key", LargeBinary(
33), index=True, nullable=False),
Column("recipient_public_key", LargeBinary(
33), index=True, nullable=True),
Column("secret_key", LargeBinary(32), nullable=True),
Column("block_time_s", Integer, nullable=False),
Column("liked_time_ms", SLBigInteger, default=None, nullable=True),

View file

@ -35,8 +35,8 @@ from sqlalchemy import or_
from sqlalchemy.sql import select
from sqlalchemy.sql import tuple_
from squeak.core import CSqueak
from squeak.core.signing import SqueakPrivateKey
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
from squeaknode.core.lightning_address import LightningAddressHostPort
from squeaknode.core.peer_address import Network
@ -84,6 +84,10 @@ class SqueakDb:
logger.debug("SqlAlchemy version: {}".format(sqlalchemy.__version__))
run_migrations(self.engine)
# Create aliases for profiles
self.author_profiles = self.profiles.alias()
self.recipient_profiles = self.profiles.alias()
def init_with_retries(
self,
num_retries=INIT_NUM_RETRIES,
@ -153,13 +157,11 @@ class SqueakDb:
return self.timestamp_now_ms > \
self.squeaks.c.created_time_ms + interval_s * 1000
@property
def profile_has_private_key(self):
return self.profiles.c.private_key != None # noqa: E711
def profile_has_private_key(self, profiles_table):
return profiles_table.c.private_key != None # noqa: E711
@property
def profile_is_following(self):
return self.profiles.c.following == True # noqa: E711
def profile_is_following(self, profiles_table):
return profiles_table.c.following == True # noqa: E711
@property
def timestamp_now_ms(self):
@ -214,11 +216,16 @@ class SqueakDb:
created_time_ms=self.timestamp_now_ms,
hash=get_hash(squeak),
squeak=squeak.serialize(),
reply_hash=squeak.hashReplySqk if squeak.is_reply else None,
reply_hash=(squeak.hashReplySqk
if squeak.is_reply
else None),
block_hash=squeak.hashBlock,
block_height=squeak.nBlockHeight,
time_s=squeak.nTime,
author_public_key=squeak.GetPubKey().to_bytes(),
recipient_public_key=(squeak.GetRecipientPubKey().to_bytes()
if squeak.is_private_message
else None),
secret_key=None,
block_time_s=block_header.nTime,
)
@ -255,12 +262,20 @@ class SqueakDb:
def get_squeak_entry(self, squeak_hash: bytes) -> Optional[SqueakEntry]:
""" Get a squeak with the author profile. """
# author_profiles = self.profiles.alias()
# recipient_profiles = self.profiles.alias()
s = (
select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
self.squeaks
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.where(self.squeaks.c.hash == squeak_hash)
@ -270,7 +285,11 @@ class SqueakDb:
row = result.fetchone()
if row is None:
return None
return self._parse_squeak_entry(row)
return self._parse_squeak_entry(
row,
# author_profiles_table=author_profiles,
# recipient_profiles_table=recipient_profiles,
)
def get_timeline_squeak_entries(
self,
@ -293,14 +312,24 @@ class SqueakDb:
last_squeak_hash.hex(),
))
s = (
select([self.squeaks, self.profiles])
# select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
# self.squeaks.outerjoin(
# self.profiles,
# self.profiles.c.public_key == self.squeaks.c.author_public_key,
# )
self.squeaks
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.where(self.profile_is_following)
.where(self.profile_is_following(self.author_profiles))
.where(
tuple_(
self.squeaks.c.block_height,
@ -342,11 +371,21 @@ class SqueakDb:
last_squeak_hash.hex(),
))
s = (
select([self.squeaks, self.profiles])
# select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
# self.squeaks.outerjoin(
# self.profiles,
# self.profiles.c.public_key == self.squeaks.c.author_public_key,
# )
self.squeaks
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.where(
@ -396,11 +435,21 @@ class SqueakDb:
last_squeak_hash.hex(),
))
s = (
select([self.squeaks, self.profiles])
# select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
# self.squeaks.outerjoin(
# self.profiles,
# self.profiles.c.public_key == self.squeaks.c.author_public_key,
# )
self.squeaks
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.where(self.squeaks.c.author_public_key == public_key.to_bytes())
@ -451,11 +500,21 @@ class SqueakDb:
last_squeak_hash.hex(),
))
s = (
select([self.squeaks, self.profiles])
# select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
# self.squeaks.outerjoin(
# self.profiles,
# self.profiles.c.public_key == self.squeaks.c.author_public_key,
# )
self.squeaks
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.where(self.squeaks.c.content.ilike(f'%{search_text}%'))
@ -508,14 +567,23 @@ class SqueakDb:
)
s = (
select([self.squeaks, self.profiles])
# select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.join(
ancestors,
ancestors.c.hash == self.squeaks.c.hash,
).outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
# ).outerjoin(
# self.profiles,
# self.profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.order_by(
@ -570,11 +638,21 @@ class SqueakDb:
last_squeak_hash.hex(),
))
s = (
select([self.squeaks, self.profiles])
# select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
# self.squeaks.outerjoin(
# self.profiles,
# self.profiles.c.public_key == self.squeaks.c.author_public_key,
# )
self.squeaks
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.where(self.squeaks.c.reply_hash == squeak_hash)
@ -694,15 +772,25 @@ class SqueakDb:
criteria for deletion.
"""
s = (
select([self.squeaks, self.profiles])
# select([self.squeaks, self.profiles])
select([self.squeaks, self.author_profiles, self.recipient_profiles])
.select_from(
self.squeaks.outerjoin(
self.profiles,
self.profiles.c.public_key == self.squeaks.c.author_public_key,
# self.squeaks.outerjoin(
# self.profiles,
# self.profiles.c.public_key == self.squeaks.c.author_public_key,
# )
self.squeaks
.outerjoin(
self.author_profiles,
self.author_profiles.c.public_key == self.squeaks.c.author_public_key,
)
.outerjoin(
self.recipient_profiles,
self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key,
)
)
.where(self.squeak_is_older_than_retention(interval_s))
.where(not_(self.profile_has_private_key))
.where(not_(self.profile_has_private_key(self.author_profiles)))
.where(not_(self.squeak_is_liked))
)
with self.get_connection() as connection:
@ -737,7 +825,10 @@ class SqueakDb:
def get_signing_profiles(self) -> List[SqueakProfile]:
""" Get all signing profiles. """
s = select([self.profiles]).where(self.profile_has_private_key)
s = (
select([self.profiles])
.where(self.profile_has_private_key(self.profiles))
)
with self.get_connection() as connection:
result = connection.execute(s)
rows = result.fetchall()
@ -746,7 +837,10 @@ class SqueakDb:
def get_contact_profiles(self) -> List[SqueakProfile]:
""" Get all contact profiles. """
s = select([self.profiles]).where(not_(self.profile_has_private_key))
s = (
select([self.profiles])
.where(not_(self.profile_has_private_key(self.profiles)))
)
with self.get_connection() as connection:
result = connection.execute(s)
rows = result.fetchall()
@ -1445,17 +1539,25 @@ class SqueakDb:
def _parse_squeak(self, row) -> CSqueak:
return CSqueak.deserialize(row["squeak"])
# def _parse_squeak_entry(self, row, author_profiles_table=None, recipient_profiles_table=None) -> SqueakEntry:
def _parse_squeak_entry(self, row) -> SqueakEntry:
public_key_bytes = row["author_public_key"]
recipient_public_key_bytes = row["recipient_public_key"]
secret_key_column = row["secret_key"]
is_locked = bool(secret_key_column)
reply_to = (
row["reply_hash"]) if row["reply_hash"] else None
liked_time_ms = row["liked_time_ms"]
profile = self._try_parse_squeak_profile(row)
profile = self._try_parse_squeak_profile(
row, profiles_table=self.author_profiles)
recipient_profile = self._try_parse_squeak_profile(
row, profiles_table=self.recipient_profiles)
return SqueakEntry(
squeak_hash=(row["hash"]),
serialized_squeak=(row["squeak"]),
public_key=SqueakPublicKey.from_bytes(row["author_public_key"]),
public_key=SqueakPublicKey.from_bytes(public_key_bytes),
recipient_public_key=SqueakPublicKey.from_bytes(
recipient_public_key_bytes) if recipient_public_key_bytes else None,
block_height=row["block_height"],
block_hash=(row["block_hash"]),
block_time=row["block_time_s"],
@ -1466,25 +1568,33 @@ class SqueakDb:
liked_time_ms=liked_time_ms,
content=row["content"],
squeak_profile=profile,
recipient_squeak_profile=recipient_profile,
)
def _parse_squeak_profile(self, row) -> SqueakProfile:
private_key_bytes = row["private_key"]
def _parse_squeak_profile(self, row, profiles_table=None) -> SqueakProfile:
profiles_table = profiles_table if (
profiles_table is not None) else self.profiles
private_key_bytes = row[profiles_table.c.private_key]
private_key = SqueakPrivateKey.from_bytes(
private_key_bytes) if private_key_bytes else None
return SqueakProfile(
profile_id=row["profile_id"],
profile_name=row["profile_name"],
profile_id=row[profiles_table.c.profile_id],
profile_name=row[profiles_table.c.profile_name],
private_key=private_key,
public_key=SqueakPublicKey.from_bytes(row["public_key"]),
following=row["following"],
profile_image=row["profile_image"],
public_key=SqueakPublicKey.from_bytes(
row[profiles_table.c.public_key]),
following=row[profiles_table.c.following],
profile_image=row[profiles_table.c.profile_image],
)
def _try_parse_squeak_profile(self, row) -> Optional[SqueakProfile]:
if row["profile_id"] is None:
def _try_parse_squeak_profile(self, row, profiles_table=None) -> Optional[SqueakProfile]:
profiles_table = profiles_table if (
profiles_table is not None) else self.profiles
if row[profiles_table.c.profile_id] is None:
return None
return self._parse_squeak_profile(row)
return self._parse_squeak_profile(row, profiles_table=profiles_table)
def _parse_squeak_peer(self, row) -> SqueakPeer:
return SqueakPeer(

View file

@ -24,7 +24,7 @@ from typing import List
from typing import Optional
from squeak.core import CSqueak
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPublicKey
from squeak.messages import msg_getdata
from squeak.messages import MSG_SECRET_KEY
from squeak.messages import MSG_SQUEAK

View file

@ -27,8 +27,8 @@ from typing import Optional
import squeak.params
from squeak.core import CSqueak
from squeak.core.signing import SqueakPrivateKey
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
from squeak.messages import msg_getdata
from squeak.messages import MsgSerializable
from squeak.net import CInterested

View file

@ -26,8 +26,8 @@ from typing import List
from typing import Optional
from squeak.core import CSqueak
from squeak.core.signing import SqueakPrivateKey
from squeak.core.signing import SqueakPublicKey
from squeak.core.keys import SqueakPrivateKey
from squeak.core.keys import SqueakPublicKey
from squeak.net import CInterested
from squeak.net import CSqueakLocator

View file

@ -65,7 +65,10 @@ def test_message_to_squeak_entry(squeak_entry_locked, squeak_entry_msg_locked):
entry = message_to_squeak_entry(squeak_entry_msg_locked)
# TODO: remove this line after implementing "message_to_squeak_profile"
entry_with_null_profile = squeak_entry_locked._replace(squeak_profile=None)
entry_with_null_profile = squeak_entry_locked\
._replace(squeak_profile=None)\
._replace(recipient_public_key=None)\
._replace(recipient_squeak_profile=None)
assert entry == entry_with_null_profile

View file

@ -22,7 +22,7 @@
import pytest
from bitcoin.core import CBlockHeader
from squeak.core.elliptic import payment_point_bytes_from_scalar_bytes
from squeak.core.signing import SqueakPrivateKey
from squeak.core.keys import SqueakPrivateKey
from squeaknode.bitcoin.block_info import BlockInfo
from squeaknode.core.connected_peer import ConnectedPeer
@ -65,6 +65,16 @@ def public_key(private_key):
yield private_key.get_public_key()
@pytest.fixture
def recipient_private_key():
yield SqueakPrivateKey.generate()
@pytest.fixture
def recipient_public_key(recipient_private_key):
yield recipient_private_key.get_public_key()
@pytest.fixture
def block_count():
yield 555
@ -142,6 +152,17 @@ def reply_squeak_and_secret_key(private_key, reply_squeak_content, block_info, s
)
@pytest.fixture
def private_squeak_and_secret_key(private_key, squeak_content, block_info, recipient_public_key):
yield make_squeak_with_block(
private_key,
squeak_content,
block_info.block_height,
block_info.block_hash,
recipient_public_key=recipient_public_key,
)
@pytest.fixture
def squeak(squeak_and_secret_key):
squeak, _ = squeak_and_secret_key
@ -190,6 +211,12 @@ def reply_squeak_hash(reply_squeak):
yield get_hash(reply_squeak)
@pytest.fixture
def private_squeak(private_squeak_and_secret_key):
squeak, _ = private_squeak_and_secret_key
yield squeak
@pytest.fixture
def peer_address():
yield PeerAddress(
@ -209,6 +236,11 @@ def contact_profile_name():
yield "fake_contact_profile_name"
@pytest.fixture
def recipient_contact_profile_name():
yield "recipient_contact_profile_name"
@pytest.fixture
def signing_profile(signing_profile_name, private_key):
yield gen_signing_profile(
@ -225,23 +257,34 @@ def contact_profile(contact_profile_name, public_key):
)
@pytest.fixture
def recipient_contact_profile(recipient_contact_profile_name, recipient_public_key):
yield gen_contact_profile(
recipient_contact_profile_name,
recipient_public_key,
)
@pytest.fixture
def squeak_entry_locked(
squeak,
squeak_bytes,
squeak_hash,
public_key,
recipient_public_key,
block_count,
block_hash,
block_time,
squeak_time,
squeak_reply_to_hash,
signing_profile,
recipient_contact_profile,
):
yield SqueakEntry(
squeak_hash=squeak_hash,
serialized_squeak=squeak_bytes,
public_key=public_key,
recipient_public_key=recipient_public_key,
block_height=block_count,
block_hash=block_hash,
block_time=block_time,
@ -250,6 +293,7 @@ def squeak_entry_locked(
is_unlocked=False,
secret_key=None,
squeak_profile=signing_profile,
recipient_squeak_profile=recipient_contact_profile,
liked_time_ms=None,
content=None,
)

View file

@ -23,6 +23,7 @@ from squeaknode.core.squeaks import check_squeak
from squeaknode.core.squeaks import get_decrypted_content
from squeaknode.core.squeaks import get_hash
from squeaknode.core.squeaks import get_payment_point_of_secret_key
from squeaknode.core.squeaks import make_squeak_with_block
def test_get_hash(squeak, squeak_hash):
@ -46,3 +47,14 @@ def test_get_decrypted_content(squeak, secret_key, squeak_content):
def test_get_payment_point_of_secret_key(squeak, secret_key):
assert get_payment_point_of_secret_key(
secret_key) == squeak.paymentPoint
def test_make_private_squeak(private_key, squeak_content, block_info):
squeak, _ = make_squeak_with_block(
private_key,
squeak_content,
block_info.block_height,
block_info.block_hash,
)
assert squeak.GetRecipientPubKey() is None

View file

@ -486,13 +486,52 @@ def test_get_missing_squeak(squeak_db, squeak, squeak_hash):
assert retrieved_squeak is None
def test_get_squeak_entry(squeak_db, squeak, block_header, public_key, inserted_squeak_hash):
def test_get_squeak_entry(
squeak_db,
squeak,
block_header,
public_key,
signing_profile,
inserted_squeak_hash,
inserted_signing_profile_id,
):
retrieved_squeak_entry = squeak_db.get_squeak_entry(inserted_squeak_hash)
assert retrieved_squeak_entry.squeak_hash == inserted_squeak_hash
assert retrieved_squeak_entry.public_key == public_key
assert retrieved_squeak_entry.content is None
assert retrieved_squeak_entry.block_time == block_header.nTime
assert retrieved_squeak_entry.squeak_profile._replace(
profile_id=None) == signing_profile
def test_get_private_squeak_entry(
squeak_db,
private_squeak,
recipient_public_key,
block_header,
public_key,
signing_profile,
recipient_contact_profile,
inserted_signing_profile_id,
):
inserted_private_squeak_hash = squeak_db.insert_squeak(
private_squeak, block_header)
squeak_db.insert_profile(
recipient_contact_profile)
retrieved_squeak_entry = squeak_db.get_squeak_entry(
inserted_private_squeak_hash)
assert retrieved_squeak_entry.squeak_hash == inserted_private_squeak_hash
assert retrieved_squeak_entry.public_key == public_key
assert retrieved_squeak_entry.content is None
assert retrieved_squeak_entry.block_time == block_header.nTime
assert retrieved_squeak_entry.squeak_profile._replace(
profile_id=None) == signing_profile
assert retrieved_squeak_entry.recipient_public_key == recipient_public_key
assert retrieved_squeak_entry.recipient_squeak_profile._replace(
profile_id=None) == recipient_contact_profile
def test_get_missing_squeak_entry(squeak_db, squeak, squeak_hash):

View file

@ -25,7 +25,7 @@ import random
import uuid
from bitcoin.core import CBlockHeader
from squeak.core.signing import SqueakPrivateKey
from squeak.core.keys import SqueakPrivateKey
from squeaknode.core.peer_address import Network
from squeaknode.core.peer_address import PeerAddress
@ -96,10 +96,10 @@ def gen_squeak_with_block_header(private_key, block_height, replyto_hash=None):
return squeak, block_info
def gen_signing_profile(profile_name, signing_key):
def gen_signing_profile(profile_name, private_key):
return create_signing_profile(
profile_name,
signing_key,
private_key,
)