forked from LBRYCommunity/lbry-sdk
channel private key generation in a thread pool
This commit is contained in:
parent
870e139fce
commit
c22482f907
7 changed files with 37 additions and 32 deletions
|
@ -2550,7 +2550,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
name, claim, amount, claim_address, funding_accounts, funding_accounts[0]
|
name, claim, amount, claim_address, funding_accounts, funding_accounts[0]
|
||||||
)
|
)
|
||||||
txo = tx.outputs[0]
|
txo = tx.outputs[0]
|
||||||
txo.generate_channel_private_key()
|
await txo.generate_channel_private_key()
|
||||||
|
|
||||||
await tx.sign(funding_accounts)
|
await tx.sign(funding_accounts)
|
||||||
|
|
||||||
|
@ -2702,7 +2702,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
|
||||||
if new_signing_key:
|
if new_signing_key:
|
||||||
new_txo.generate_channel_private_key()
|
await new_txo.generate_channel_private_key()
|
||||||
else:
|
else:
|
||||||
new_txo.private_key = old_txo.private_key
|
new_txo.private_key = old_txo.private_key
|
||||||
|
|
||||||
|
|
|
@ -525,11 +525,13 @@ class Account:
|
||||||
channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes)
|
channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes)
|
||||||
self.channel_keys[channel_pubkey_hash] = private_key.to_pem().decode()
|
self.channel_keys[channel_pubkey_hash] = private_key.to_pem().decode()
|
||||||
|
|
||||||
def get_channel_private_key(self, public_key_bytes):
|
async def get_channel_private_key(self, public_key_bytes):
|
||||||
channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes)
|
channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes)
|
||||||
private_key_pem = self.channel_keys.get(channel_pubkey_hash)
|
private_key_pem = self.channel_keys.get(channel_pubkey_hash)
|
||||||
if private_key_pem:
|
if private_key_pem:
|
||||||
return ecdsa.SigningKey.from_pem(private_key_pem, hashfunc=sha256)
|
return await asyncio.get_event_loop().run_in_executor(
|
||||||
|
None, ecdsa.SigningKey.from_pem, private_key_pem, sha256
|
||||||
|
)
|
||||||
|
|
||||||
async def maybe_migrate_certificates(self):
|
async def maybe_migrate_certificates(self):
|
||||||
def to_der(private_key_pem):
|
def to_der(private_key_pem):
|
||||||
|
|
|
@ -918,7 +918,7 @@ class Database(SQLiteMixin):
|
||||||
channel_ids.add(txo.claim.signing_channel_id)
|
channel_ids.add(txo.claim.signing_channel_id)
|
||||||
if txo.claim.is_channel and wallet:
|
if txo.claim.is_channel and wallet:
|
||||||
for account in wallet.accounts:
|
for account in wallet.accounts:
|
||||||
private_key = account.get_channel_private_key(
|
private_key = await account.get_channel_private_key(
|
||||||
txo.claim.channel.public_key_bytes
|
txo.claim.channel.public_key_bytes
|
||||||
)
|
)
|
||||||
if private_key:
|
if private_key:
|
||||||
|
|
|
@ -2,6 +2,7 @@ import struct
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
|
import asyncio
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from typing import List, Iterable, Optional, Tuple
|
from typing import List, Iterable, Optional, Tuple
|
||||||
|
|
||||||
|
@ -412,8 +413,10 @@ class Output(InputOutput):
|
||||||
self.channel = None
|
self.channel = None
|
||||||
self.claim.clear_signature()
|
self.claim.clear_signature()
|
||||||
|
|
||||||
def generate_channel_private_key(self):
|
async def generate_channel_private_key(self):
|
||||||
self.private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256)
|
self.private_key = await asyncio.get_event_loop().run_in_executor(
|
||||||
|
None, ecdsa.SigningKey.generate, ecdsa.SECP256k1, None, hashlib.sha256
|
||||||
|
)
|
||||||
self.claim.channel.public_key_bytes = self.private_key.get_verifying_key().to_der()
|
self.claim.channel.public_key_bytes = self.private_key.get_verifying_key().to_der()
|
||||||
self.script.generate()
|
self.script.generate()
|
||||||
return self.private_key
|
return self.private_key
|
||||||
|
|
|
@ -31,7 +31,7 @@ class BasicTransactionTest(IntegrationTestCase):
|
||||||
channel_txo = Output.pay_claim_name_pubkey_hash(
|
channel_txo = Output.pay_claim_name_pubkey_hash(
|
||||||
l2d('1.0'), '@bar', channel, self.account.ledger.address_to_hash160(address1)
|
l2d('1.0'), '@bar', channel, self.account.ledger.address_to_hash160(address1)
|
||||||
)
|
)
|
||||||
channel_txo.generate_channel_private_key()
|
await channel_txo.generate_channel_private_key()
|
||||||
channel_txo.script.generate()
|
channel_txo.script.generate()
|
||||||
channel_tx = await Transaction.create([], [channel_txo], [self.account], self.account)
|
channel_tx = await Transaction.create([], [channel_txo], [self.account], self.account)
|
||||||
|
|
||||||
|
|
|
@ -18,31 +18,31 @@ class TestSigningComments(AsyncioTestCase):
|
||||||
'comment_id': hashlib.sha256(comment.encode()).hexdigest()
|
'comment_id': hashlib.sha256(comment.encode()).hexdigest()
|
||||||
}
|
}
|
||||||
|
|
||||||
def test01_successful_create_sign_and_validate_comment(self):
|
async def test01_successful_create_sign_and_validate_comment(self):
|
||||||
channel = get_channel('@BusterBluth')
|
channel = await get_channel('@BusterBluth')
|
||||||
stream = get_stream('pop secret')
|
stream = get_stream('pop secret')
|
||||||
comment = self.create_claim_comment_body('Cool stream', stream, channel)
|
comment = self.create_claim_comment_body('Cool stream', stream, channel)
|
||||||
sign_comment(comment, channel)
|
sign_comment(comment, channel)
|
||||||
self.assertTrue(is_comment_signed_by_channel(comment, channel))
|
self.assertTrue(is_comment_signed_by_channel(comment, channel))
|
||||||
|
|
||||||
def test02_fail_to_validate_spoofed_channel(self):
|
async def test02_fail_to_validate_spoofed_channel(self):
|
||||||
pdiddy = get_channel('@PDitty')
|
pdiddy = await get_channel('@PDitty')
|
||||||
channel2 = get_channel('@TomHaverford')
|
channel2 = await get_channel('@TomHaverford')
|
||||||
stream = get_stream()
|
stream = get_stream()
|
||||||
comment = self.create_claim_comment_body('Woahh This is Sick!! Shout out 2 my boy Tommy H', stream, pdiddy)
|
comment = self.create_claim_comment_body('Woahh This is Sick!! Shout out 2 my boy Tommy H', stream, pdiddy)
|
||||||
sign_comment(comment, channel2)
|
sign_comment(comment, channel2)
|
||||||
self.assertFalse(is_comment_signed_by_channel(comment, pdiddy))
|
self.assertFalse(is_comment_signed_by_channel(comment, pdiddy))
|
||||||
|
|
||||||
def test03_successful_sign_abandon_comment(self):
|
async def test03_successful_sign_abandon_comment(self):
|
||||||
rswanson = get_channel('@RonSwanson')
|
rswanson = await get_channel('@RonSwanson')
|
||||||
dsilver = get_stream('Welcome to the Pawnee, and give a big round for Ron Swanson, AKA Duke Silver')
|
dsilver = get_stream('Welcome to the Pawnee, and give a big round for Ron Swanson, AKA Duke Silver')
|
||||||
comment_body = self.create_claim_comment_body('COMPUTER, DELETE ALL VIDEOS OF RON.', dsilver, rswanson)
|
comment_body = self.create_claim_comment_body('COMPUTER, DELETE ALL VIDEOS OF RON.', dsilver, rswanson)
|
||||||
sign_comment(comment_body, rswanson, abandon=True)
|
sign_comment(comment_body, rswanson, abandon=True)
|
||||||
self.assertTrue(is_comment_signed_by_channel(comment_body, rswanson, abandon=True))
|
self.assertTrue(is_comment_signed_by_channel(comment_body, rswanson, abandon=True))
|
||||||
|
|
||||||
def test04_invalid_signature(self):
|
async def test04_invalid_signature(self):
|
||||||
rswanson = get_channel('@RonSwanson')
|
rswanson = await get_channel('@RonSwanson')
|
||||||
jeanralphio = get_channel('@JeanRalphio')
|
jeanralphio = await get_channel('@JeanRalphio')
|
||||||
chair = get_stream('This is a nice chair. I made it with Mahogany wood and this electric saw')
|
chair = get_stream('This is a nice chair. I made it with Mahogany wood and this electric saw')
|
||||||
chair_comment = self.create_claim_comment_body(
|
chair_comment = self.create_claim_comment_body(
|
||||||
'Hah. You use an electric saw? Us swansons have been making chairs with handsaws just three after birth.',
|
'Hah. You use an electric saw? Us swansons have been making chairs with handsaws just three after birth.',
|
||||||
|
|
|
@ -21,9 +21,9 @@ def get_tx():
|
||||||
return Transaction().add_inputs([get_input()])
|
return Transaction().add_inputs([get_input()])
|
||||||
|
|
||||||
|
|
||||||
def get_channel(claim_name='@foo'):
|
async def get_channel(claim_name='@foo'):
|
||||||
channel_txo = Output.pay_claim_name_pubkey_hash(CENT, claim_name, Claim(), b'abc')
|
channel_txo = Output.pay_claim_name_pubkey_hash(CENT, claim_name, Claim(), b'abc')
|
||||||
channel_txo.generate_channel_private_key()
|
await channel_txo.generate_channel_private_key()
|
||||||
get_tx().add_outputs([channel_txo])
|
get_tx().add_outputs([channel_txo])
|
||||||
return channel_txo
|
return channel_txo
|
||||||
|
|
||||||
|
@ -36,32 +36,32 @@ def get_stream(claim_name='foo'):
|
||||||
|
|
||||||
class TestSigningAndValidatingClaim(AsyncioTestCase):
|
class TestSigningAndValidatingClaim(AsyncioTestCase):
|
||||||
|
|
||||||
def test_successful_create_sign_and_validate(self):
|
async def test_successful_create_sign_and_validate(self):
|
||||||
channel = get_channel()
|
channel = await get_channel()
|
||||||
stream = get_stream()
|
stream = get_stream()
|
||||||
stream.sign(channel)
|
stream.sign(channel)
|
||||||
self.assertTrue(stream.is_signed_by(channel))
|
self.assertTrue(stream.is_signed_by(channel))
|
||||||
|
|
||||||
def test_fail_to_validate_on_wrong_channel(self):
|
async def test_fail_to_validate_on_wrong_channel(self):
|
||||||
stream = get_stream()
|
stream = get_stream()
|
||||||
stream.sign(get_channel())
|
stream.sign(await get_channel())
|
||||||
self.assertFalse(stream.is_signed_by(get_channel()))
|
self.assertFalse(stream.is_signed_by(await get_channel()))
|
||||||
|
|
||||||
def test_fail_to_validate_altered_claim(self):
|
async def test_fail_to_validate_altered_claim(self):
|
||||||
channel = get_channel()
|
channel = await get_channel()
|
||||||
stream = get_stream()
|
stream = get_stream()
|
||||||
stream.sign(channel)
|
stream.sign(channel)
|
||||||
self.assertTrue(stream.is_signed_by(channel))
|
self.assertTrue(stream.is_signed_by(channel))
|
||||||
stream.claim.stream.title = 'hello'
|
stream.claim.stream.title = 'hello'
|
||||||
self.assertFalse(stream.is_signed_by(channel))
|
self.assertFalse(stream.is_signed_by(channel))
|
||||||
|
|
||||||
def test_valid_private_key_for_cert(self):
|
async def test_valid_private_key_for_cert(self):
|
||||||
channel = get_channel()
|
channel = await get_channel()
|
||||||
self.assertTrue(channel.is_channel_private_key(channel.private_key))
|
self.assertTrue(channel.is_channel_private_key(channel.private_key))
|
||||||
|
|
||||||
def test_fail_to_load_wrong_private_key_for_cert(self):
|
async def test_fail_to_load_wrong_private_key_for_cert(self):
|
||||||
channel = get_channel()
|
channel = await get_channel()
|
||||||
self.assertFalse(channel.is_channel_private_key(get_channel().private_key))
|
self.assertFalse(channel.is_channel_private_key((await get_channel()).private_key))
|
||||||
|
|
||||||
|
|
||||||
class TestValidatingOldSignatures(AsyncioTestCase):
|
class TestValidatingOldSignatures(AsyncioTestCase):
|
||||||
|
|
Loading…
Reference in a new issue