work in progress
This commit is contained in:
parent
e4cc4521d9
commit
8216f4a873
6 changed files with 87 additions and 2 deletions
|
@ -126,6 +126,10 @@ class PubKey(_KeyBase):
|
|||
self.pubkey_bytes
|
||||
)
|
||||
|
||||
def verify(self, signature, data):
|
||||
""" Produce a signature for piece of data by double hashing it and signing the hash. """
|
||||
return self.verifying_key.verify(signature, data, hasher=double_sha256)
|
||||
|
||||
|
||||
class PrivateKey(_KeyBase):
|
||||
"""A BIP32 private key."""
|
||||
|
|
|
@ -1244,7 +1244,7 @@ class Database(SQLiteMixin):
|
|||
async def is_channel_key_used(self, wallet, address):
|
||||
channels = await self.get_txos(wallet, txo_type=TXO_TYPES['channel'])
|
||||
for channel in channels:
|
||||
if channel.private_key.address() == address:
|
||||
if channel.private_key is not None and channel.private_key.address() == address:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -470,6 +470,7 @@ class Ledger(metaclass=LedgerRegistry):
|
|||
for address_manager in account.address_managers.values():
|
||||
await self.subscribe_addresses(address_manager, await address_manager.get_addresses())
|
||||
await account.ensure_address_gap()
|
||||
await account.deterministic_channel_keys.ensure_cache_primed()
|
||||
|
||||
async def unsubscribe_account(self, account: Account):
|
||||
for address in await account.get_addresses():
|
||||
|
|
|
@ -28,6 +28,7 @@ from .constants import COIN, NULL_HASH32
|
|||
from .bcd_data_stream import BCDataStream
|
||||
from .hash import TXRef, TXRefImmutable
|
||||
from .util import ReadOnlyList
|
||||
from .bip32 import PubKey
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from lbry.wallet.account import Account
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
from binascii import unhexlify
|
||||
|
||||
from lbry.testcase import CommandTestCase
|
||||
from lbry.wallet.dewies import dewies_to_lbc
|
||||
from lbry.wallet.account import DeterministicChannelKeyManager
|
||||
from lbry.wallet.transaction import Transaction
|
||||
|
||||
|
||||
def extract(d, keys):
|
||||
|
@ -175,8 +179,17 @@ class AccountManagement(CommandTestCase):
|
|||
with self.assertRaisesRegex(Exception, f"'{bad_address}' is not a valid address"):
|
||||
await self.daemon.jsonrpc_account_send('0.1', addresses=[bad_address])
|
||||
|
||||
async def test_backwards_compatibility(self):
|
||||
pk = {
|
||||
'mpAt7RQJUWe3RWPyyYQ9cinQoPH9HomPdh':
|
||||
'-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIMrKg13+6mj5zdqN2wCx24GgYD8PUiYVzGewgOvu24SfoA'
|
||||
'cGBSuBBAAK\noUQDQgAE1/oT/Y5X86C4eOqvPReRRNJd2+Sj5EQKZh9RtBNMahPJyYZ4/4QRky5g\n/ZfXuvA+'
|
||||
'pn68whCXIwz7IkE0iq21Xg==\n-----END EC PRIVATE KEY-----\n'
|
||||
}
|
||||
|
||||
async def test_deterministic_channel_keys(self):
|
||||
seed = self.account.seed
|
||||
keys = self.account.deterministic_channel_keys
|
||||
|
||||
# create two channels and make sure they have different keys
|
||||
channel1a = await self.channel_create('@foo1')
|
||||
|
@ -202,11 +215,41 @@ class AccountManagement(CommandTestCase):
|
|||
channel2b.private_key.public_key.address
|
||||
)
|
||||
|
||||
# repeatedly calling next channel key returns the same key when not used
|
||||
current_known = keys.last_known
|
||||
next_key = await keys.generate_next_key()
|
||||
self.assertEqual(current_known, keys.last_known)
|
||||
self.assertEqual(next_key.address(), (await keys.generate_next_key()).address())
|
||||
# again, should be idempotent
|
||||
next_key = await keys.generate_next_key()
|
||||
self.assertEqual(current_known, keys.last_known)
|
||||
self.assertEqual(next_key.address(), (await keys.generate_next_key()).address())
|
||||
|
||||
# create third channel while both daemons running, second daemon should pick it up
|
||||
channel3a = await self.channel_create('@foo3')
|
||||
self.assertEqual(current_known+1, keys.last_known)
|
||||
self.assertNotEqual(next_key.address(), (await keys.generate_next_key()).address())
|
||||
channel3b, = (await self.daemon2.jsonrpc_channel_list(name='@foo3'))['items']
|
||||
self.assertTrue(channel3b.has_private_key)
|
||||
self.assertEqual(
|
||||
channel3a['outputs'][0]['value']['public_key_id'],
|
||||
channel3b.private_key.public_key.address
|
||||
)
|
||||
|
||||
# channel key cache re-populated after simulated restart
|
||||
|
||||
# reset cache
|
||||
self.account.deterministic_channel_keys = DeterministicChannelKeyManager(self.account)
|
||||
channel3c, channel2c, channel1c = (await self.daemon.jsonrpc_channel_list())['items']
|
||||
self.assertFalse(channel1c.has_private_key)
|
||||
self.assertFalse(channel2c.has_private_key)
|
||||
self.assertFalse(channel3c.has_private_key)
|
||||
|
||||
# repopulate cache
|
||||
await self.account.deterministic_channel_keys.ensure_cache_primed()
|
||||
self.assertEqual(self.account.deterministic_channel_keys.last_known, keys.last_known)
|
||||
channel3c, channel2c, channel1c = (await self.daemon.jsonrpc_channel_list())['items']
|
||||
self.assertTrue(channel1c.has_private_key)
|
||||
self.assertTrue(channel2c.has_private_key)
|
||||
self.assertTrue(channel3c.has_private_key)
|
||||
|
||||
|
|
|
@ -2,10 +2,13 @@ from binascii import unhexlify
|
|||
|
||||
from lbry.testcase import AsyncioTestCase
|
||||
from lbry.wallet.constants import CENT, NULL_HASH32
|
||||
from lbry.wallet.bip32 import PrivateKey
|
||||
from lbry.wallet.mnemonic import Mnemonic
|
||||
from lbry.wallet import Ledger, Database, Headers, Transaction, Input, Output
|
||||
from lbry.schema.claim import Claim
|
||||
from lbry.crypto.hash import sha256
|
||||
|
||||
|
||||
def get_output(amount=CENT, pubkey_hash=NULL_HASH32):
|
||||
return Transaction() \
|
||||
.add_outputs([Output.pay_pubkey_hash(amount, pubkey_hash)]) \
|
||||
|
@ -22,7 +25,9 @@ def get_tx():
|
|||
|
||||
async def get_channel(claim_name='@foo'):
|
||||
channel_txo = Output.pay_claim_name_pubkey_hash(CENT, claim_name, Claim(), b'abc')
|
||||
await channel_txo.generate_channel_private_key()
|
||||
channel_txo.set_channel_private_key(PrivateKey.from_seed(
|
||||
Ledger, Mnemonic.mnemonic_to_seed(Mnemonic().make_seed(), '')
|
||||
))
|
||||
get_tx().add_outputs([channel_txo])
|
||||
return channel_txo
|
||||
|
||||
|
@ -114,6 +119,37 @@ class TestValidatingOldSignatures(AsyncioTestCase):
|
|||
|
||||
self.assertTrue(stream.is_signed_by(channel, ledger))
|
||||
|
||||
def test_claim_signed_using_ecdsa_validates_with_coincurve(self):
|
||||
channel_tx = Transaction(unhexlify(
|
||||
"0100000001b91d829283c0d80cb8113d5f36b6da3dfe9df3e783f158bfb3fd1b2b178d7fc9010000006b48"
|
||||
"3045022100f4e2b4ee38388c3d3a62f4b12fdd413f6f140168e85884bbeb33a3f2d3159ef502201721200f"
|
||||
"4a4f3b87484d4f47c9054e31cd3ba451dd3886a7f9f854893e7c8cf90121023f9e906e0c120f3bf74feb40"
|
||||
"f01ddeafbeb1856d91938c3bef25bed06767247cffffffff0200e1f5050000000081b505406368616e4c5d"
|
||||
"00125a0a583056301006072a8648ce3d020106052b8104000a03420004d7fa13fd8e57f3a0b878eaaf3d17"
|
||||
"9144d25ddbe4a3e4440a661f51b4134c6a13c9c98678ff8411932e60fd97d7baf03ea67ebcc21097230cfb"
|
||||
"2241348aadb55e6d7576a9149c6d700f89c77f0e8c650ba05656f8f2392782d388acf47c95350000000019"
|
||||
"76a914d9502233e0e1fc76e13e36c546f704c3124d5eaa88ac00000000"
|
||||
))
|
||||
channel = channel_tx.outputs[0]
|
||||
|
||||
stream_tx = Transaction(unhexlify(
|
||||
"010000000116a1d90763f2e3a2348c7fb438a23f232b15e3ffe3f058c3b2ab52c8bed8dcb5010000006b48"
|
||||
"30450221008f38561b3a16944c63b4f4f1562f1efe1b2060f31d249e234003ee5e3461756f02205773c99e"
|
||||
"83c968728e4f2433a13871c6ad23f6c10368ac52fa62a09f3f7ef5fd012102597f39845b98e2415b777aa0"
|
||||
"3849d346d287af7970deb05f11214b3418ae9d82ffffffff0200e1f50500000000fd0c01b505636c61696d"
|
||||
"4ce8012e6e40fa5fee1b915af3b55131dcbcebee34ab9148292b084ce3741f2e0db49783f3d854ac885f2b"
|
||||
"6304a76ef7048046e338dd414ba4c64e8468651768ffaaf550c8560637ac8c477ea481ac2a9264097240f4"
|
||||
"ab0a90010a8d010a3056bf5dbae43f77a63d075b0f2ae9c7c3e3098db93779c7f9840da0f4db9c2f8c8454"
|
||||
"f4edd1373e2b64ee2e68350d916e120b746d706c69647879363171180322186170706c69636174696f6e2f"
|
||||
"6f637465742d73747265616d3230f293f5acf4310562d4a41f6620167fe6d83761a98d36738908ce5c8776"
|
||||
"1642710e55352a396276a42eda92ff5856f46f6d7576a91434bd3dc4c45cc0635eb2ad5da658727e5442ca"
|
||||
"0f88ace82f902f000000001976a91427b27c89eaebf68d063c107241584c07e5a6ccc688ac00000000"
|
||||
))
|
||||
stream = stream_tx.outputs[0]
|
||||
|
||||
ledger = Ledger({'db': Database(':memory:'), 'headers': Headers(':memory:')})
|
||||
self.assertTrue(stream.is_signed_by(channel, ledger))
|
||||
|
||||
|
||||
class TestValidateSignContent(AsyncioTestCase):
|
||||
|
||||
|
|
Loading…
Reference in a new issue