adds jsonrpc_channel_sign signing api

This commit is contained in:
Victor Shyba 2020-12-24 01:55:58 -03:00
parent 42ad2bb83f
commit 6da6bdc863
2 changed files with 55 additions and 1 deletions

View file

@ -21,6 +21,8 @@ import base58
from aiohttp import web
from prometheus_client import generate_latest as prom_generate_latest, Gauge, Histogram, Counter
from google.protobuf.message import DecodeError
from lbry.crypto.hash import sha256
from lbry.wallet import (
Wallet, ENCRYPT_ON_DISK, SingleKey, HierarchicalDeterministic,
Transaction, Output, Input, Account, database
@ -2788,6 +2790,40 @@ class Daemon(metaclass=JSONRPCServerType):
return tx
@requires(WALLET_COMPONENT)
async def jsonrpc_channel_sign(
self, channel_name=None, channel_id=None, hexdata=None, channel_account_id=None, wallet_id=None):
"""
Signs data using the specified channel signing key.
Usage:
channel_sign [<channel_name> | --channel_name=<channel_name>]
[<channel_id> | --channel_id=<channel_id>] [<hexdata> | --hexdata=<hexdata>]
[--channel_account_id=<channel_account_id>...] [--wallet_id=<wallet_id>]
Options:
--channel_name=<channel_name> : (str) name of channel used to sign (or use channel id)
--channel_id=<channel_id> : (str) claim id of channel used to sign (or use channel name)
--hexdata=<hexdata> : (str) data to sign, encoded as hexadecimal
--channel_account_id=<channel_account_id>: (str) one or more account ids for accounts to look in
for channel certificates, defaults to all accounts.
--wallet_id=<wallet_id> : (str) restrict operation to specific wallet
Returns: {}
"""
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
assert not wallet.is_locked, "Cannot spend funds with locked wallet, unlock first."
signing_channel = await self.get_channel_or_error(
wallet, channel_account_id, channel_id, channel_name, for_signing=True
)
digest = sha256(unhexlify(hexdata))
signature = signing_channel.private_key.sign_digest_deterministic(digest, hashfunc=hashlib.sha256)
return {
"signature": hexlify(signature),
"digest": hexlify(digest),
"signing_channel": signing_channel
}
@requires(WALLET_COMPONENT)
async def jsonrpc_channel_abandon(
self, claim_id=None, txid=None, nout=None, account_id=None, wallet_id=None,

View file

@ -5,11 +5,13 @@ import asyncio
from binascii import unhexlify
from urllib.request import urlopen
import ecdsa
from lbry.error import InsufficientFundsError
from lbry.extras.daemon.daemon import DEFAULT_PAGE_SIZE
from lbry.testcase import CommandTestCase
from lbry.wallet.transaction import Transaction
from lbry.wallet.transaction import Transaction, Output
from lbry.wallet.util import satoshis_to_coins as lbc
@ -1004,6 +1006,22 @@ class ChannelCommands(CommandTestCase):
self.assertItemCount(await self.daemon.jsonrpc_channel_list(account_id=self.account.id), 2)
self.assertItemCount(await self.daemon.jsonrpc_channel_list(account_id=account2_id), 1)
async def test_sign_hex_encoded_data(self):
data_to_sign = "CAFEBABE"
# claim new name
await self.channel_create('@someotherchan')
channel_tx = await self.channel_create('@signer')
channel_id = self.get_claim_id(channel_tx)
signature1 = await self.out(self.daemon.jsonrpc_channel_sign(channel_name='@signer', hexdata=data_to_sign))
signature2 = await self.out(self.daemon.jsonrpc_channel_sign(channel_id=channel_id, hexdata=data_to_sign))
self.assertEqual(signature2, signature1)
key = unhexlify(channel_tx['outputs'][0]['value']['public_key'])
signature = signature1["signature"]
r = int(signature[:int(len(signature)/2)], 16)
s = int(signature[int(len(signature)/2):], 16)
signature = ecdsa.util.sigencode_der(r, s, len(signature)*4)
self.assertTrue(Output.is_signature_valid(signature, unhexlify(signature1["digest"]), key))
async def test_channel_export_import_before_sending_channel(self):
# export
tx = await self.channel_create('@foo', '1.0')