forked from LBRYCommunity/lbry-sdk
all
This commit is contained in:
parent
e74998209d
commit
6653da2973
11 changed files with 42 additions and 15 deletions
|
@ -77,6 +77,7 @@ class JSONResponseEncoder(JSONEncoder):
|
||||||
if txo.channel is not None:
|
if txo.channel is not None:
|
||||||
output['channel_name'] = txo.channel.claim_name
|
output['channel_name'] = txo.channel.claim_name
|
||||||
try:
|
try:
|
||||||
|
raise ValueError()
|
||||||
output['valid_signature'] = txo.is_signed_by(txo.channel, self.ledger)
|
output['valid_signature'] = txo.is_signed_by(txo.channel, self.ledger)
|
||||||
except BadSignatureError:
|
except BadSignatureError:
|
||||||
output['valid_signature'] = False
|
output['valid_signature'] = False
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
from google.protobuf.message import DecodeError
|
from google.protobuf.message import DecodeError
|
||||||
from google.protobuf.json_format import MessageToDict
|
from google.protobuf.json_format import MessageToDict
|
||||||
|
|
||||||
|
@ -23,6 +25,10 @@ class Signable:
|
||||||
def is_undetermined(self):
|
def is_undetermined(self):
|
||||||
return self.message.WhichOneof('type') is None
|
return self.message.WhichOneof('type') is None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def signing_channel_hash(self):
|
||||||
|
return hexlify(self.signing_channel_id[::-1]).decode() if self.signing_channel_id else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_signed(self):
|
def is_signed(self):
|
||||||
return self.signature is not None
|
return self.signature is not None
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
from torba.client.basedatabase import BaseDatabase
|
from torba.client.basedatabase import BaseDatabase
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,7 +59,7 @@ class WalletDatabase(BaseDatabase):
|
||||||
for txo in txos:
|
for txo in txos:
|
||||||
if txo.script.is_claim_name or txo.script.is_update_claim:
|
if txo.script.is_claim_name or txo.script.is_update_claim:
|
||||||
if txo.claim.is_signed:
|
if txo.claim.is_signed:
|
||||||
channel_ids.add(txo.claim.signing_channel_id)
|
channel_ids.add(hexlify(txo.claim.signing_channel_id[::-1]).decode())
|
||||||
if txo.claim_name.startswith('@') and my_account is not None:
|
if txo.claim_name.startswith('@') and my_account is not None:
|
||||||
txo.private_key = my_account.get_certificate_private_key(txo.ref)
|
txo.private_key = my_account.get_certificate_private_key(txo.ref)
|
||||||
|
|
||||||
|
@ -71,8 +73,7 @@ class WalletDatabase(BaseDatabase):
|
||||||
}
|
}
|
||||||
for txo in txos:
|
for txo in txos:
|
||||||
if txo.script.is_claim_name or txo.script.is_update_claim:
|
if txo.script.is_claim_name or txo.script.is_update_claim:
|
||||||
if 'publisherSignature' in txo.claim_dict:
|
txo.channel = channels.get(txo.claim.signing_channel_hash, None)
|
||||||
txo.channel = channels.get(txo.claim_dict['publisherSignature']['certificateId'])
|
|
||||||
|
|
||||||
return txos
|
return txos
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ class MainNetLedger(BaseLedger):
|
||||||
resolutions = await self.network.get_values_for_uris(self.headers.hash().decode(), *uris)
|
resolutions = await self.network.get_values_for_uris(self.headers.hash().decode(), *uris)
|
||||||
return await resolver._handle_resolutions(resolutions, uris, page, page_size)
|
return await resolver._handle_resolutions(resolutions, uris, page, page_size)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
log.exception(e)
|
||||||
return {'error': str(e)}
|
return {'error': str(e)}
|
||||||
|
|
||||||
async def get_claim_by_claim_id(self, claim_id):
|
async def get_claim_by_claim_id(self, claim_id):
|
||||||
|
|
|
@ -416,12 +416,13 @@ class LbryWalletManager(BaseWalletManager):
|
||||||
|
|
||||||
if certificate:
|
if certificate:
|
||||||
claim_output.sign(certificate, first_input_id=b'placeholder')
|
claim_output.sign(certificate, first_input_id=b'placeholder')
|
||||||
|
claim_output.script.generate()
|
||||||
|
|
||||||
tx = await Transaction.create(inputs, [claim_output], [account], account)
|
tx = await Transaction.create(inputs, [claim_output], [account], account)
|
||||||
|
|
||||||
if certificate:
|
if certificate:
|
||||||
claim_output.sign(certificate)
|
claim_output.sign(certificate)
|
||||||
tx._reset()
|
await tx.sign([account])
|
||||||
|
|
||||||
await account.ledger.broadcast(tx)
|
await account.ledger.broadcast(tx)
|
||||||
await self.old_db.save_claims([self._old_get_temp_claim_info(
|
await self.old_db.save_claims([self._old_get_temp_claim_info(
|
||||||
|
@ -475,8 +476,10 @@ class LbryWalletManager(BaseWalletManager):
|
||||||
amount, channel_name, claim, account.ledger.address_to_hash160(address)
|
amount, channel_name, claim, account.ledger.address_to_hash160(address)
|
||||||
)
|
)
|
||||||
key = claim_output.generate_channel_private_key()
|
key = claim_output.generate_channel_private_key()
|
||||||
|
claim_output.script.generate()
|
||||||
tx = await Transaction.create([], [claim_output], [account], account)
|
tx = await Transaction.create([], [claim_output], [account], account)
|
||||||
|
|
||||||
|
|
||||||
await account.ledger.broadcast(tx)
|
await account.ledger.broadcast(tx)
|
||||||
account.add_certificate_private_key(tx.outputs[0].ref, key.decode())
|
account.add_certificate_private_key(tx.outputs[0].ref, key.decode())
|
||||||
# TODO: release reserved tx outputs in case anything fails by this point
|
# TODO: release reserved tx outputs in case anything fails by this point
|
||||||
|
|
|
@ -8,6 +8,8 @@ from lbrynet.schema.claim import Claim
|
||||||
from google.protobuf.message import DecodeError
|
from google.protobuf.message import DecodeError
|
||||||
from lbrynet.schema.uri import parse_lbry_uri
|
from lbrynet.schema.uri import parse_lbry_uri
|
||||||
from lbrynet.wallet.claim_proofs import verify_proof, InvalidProofError
|
from lbrynet.wallet.claim_proofs import verify_proof, InvalidProofError
|
||||||
|
from lbrynet.wallet.transaction import Transaction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@ class Resolver:
|
||||||
await self._handle_resolve_uri_response(uri, resolution, page, page_size)
|
await self._handle_resolve_uri_response(uri, resolution, page, page_size)
|
||||||
)
|
)
|
||||||
except (UnknownNameError, UnknownClaimID, UnknownURI) as err:
|
except (UnknownNameError, UnknownClaimID, UnknownURI) as err:
|
||||||
|
log.exception(err)
|
||||||
results[uri] = {'error': str(err)}
|
results[uri] = {'error': str(err)}
|
||||||
else:
|
else:
|
||||||
results[uri] = {'error': "URI lbry://{} cannot be resolved".format(uri.replace("lbry://", ""))}
|
results[uri] = {'error': "URI lbry://{} cannot be resolved".format(uri.replace("lbry://", ""))}
|
||||||
|
@ -151,8 +154,9 @@ class Resolver:
|
||||||
if not claim_result or 'value' not in claim_result:
|
if not claim_result or 'value' not in claim_result:
|
||||||
return claim_result
|
return claim_result
|
||||||
certificate = None
|
certificate = None
|
||||||
certificate_id = Claim.from_bytes(claim_result['value']).signing_channel_id
|
certificate_id = Claim.from_bytes(unhexlify(claim_result['value'])).signing_channel_id
|
||||||
if certificate_id:
|
if certificate_id:
|
||||||
|
certificate_id = hexlify(certificate_id[::-1]).decode()
|
||||||
certificate = await self.network.get_claims_by_ids(certificate_id)
|
certificate = await self.network.get_claims_by_ids(certificate_id)
|
||||||
certificate = certificate.pop(certificate_id) if certificate else None
|
certificate = certificate.pop(certificate_id) if certificate else None
|
||||||
return await self.parse_and_validate_claim_result(claim_result, certificate=certificate)
|
return await self.parse_and_validate_claim_result(claim_result, certificate=certificate)
|
||||||
|
@ -175,6 +179,8 @@ class Resolver:
|
||||||
if decoded:
|
if decoded:
|
||||||
claim_result['has_signature'] = False
|
claim_result['has_signature'] = False
|
||||||
if decoded.is_signed:
|
if decoded.is_signed:
|
||||||
|
claim_tx = await self.network.get_transaction(claim_result['txid'])
|
||||||
|
cert_tx = await self.network.get_transaction(certificate['txid'])
|
||||||
if certificate is None:
|
if certificate is None:
|
||||||
log.info("fetching certificate to check claim signature")
|
log.info("fetching certificate to check claim signature")
|
||||||
certificate = await self.network.get_claims_by_ids(decoded.signing_channel_id)
|
certificate = await self.network.get_claims_by_ids(decoded.signing_channel_id)
|
||||||
|
@ -183,7 +189,9 @@ class Resolver:
|
||||||
claim_result['has_signature'] = True
|
claim_result['has_signature'] = True
|
||||||
claim_result['signature_is_valid'] = False
|
claim_result['signature_is_valid'] = False
|
||||||
validated, channel_name = validate_claim_signature_and_get_channel_name(
|
validated, channel_name = validate_claim_signature_and_get_channel_name(
|
||||||
decoded, certificate, claim_result['address'], claim_result['name'])
|
claim_result, certificate, claim_result['address'], claim_result['name'],
|
||||||
|
claim_tx=claim_tx, cert_tx=cert_tx
|
||||||
|
)
|
||||||
claim_result['channel_name'] = channel_name
|
claim_result['channel_name'] = channel_name
|
||||||
if validated:
|
if validated:
|
||||||
claim_result['signature_is_valid'] = True
|
claim_result['signature_is_valid'] = True
|
||||||
|
@ -382,14 +390,21 @@ def _verify_proof(name, claim_trie_root, result, height, depth, transaction_clas
|
||||||
return {'error': "proof not in result"}
|
return {'error': "proof not in result"}
|
||||||
|
|
||||||
|
|
||||||
def validate_claim_signature_and_get_channel_name(claim, certificate_claim,
|
def validate_claim_signature_and_get_channel_name(claim_result, certificate_claim,
|
||||||
claim_address, name, decoded_certificate=None):
|
claim_address, name, decoded_certificate=None,
|
||||||
|
claim_tx=None, cert_tx=None):
|
||||||
|
if cert_tx and certificate_claim and claim_tx and claim_result:
|
||||||
|
tx = Transaction(unhexlify(claim_tx))
|
||||||
|
cert_tx = Transaction(unhexlify(cert_tx))
|
||||||
|
is_signed = tx.outputs[claim_result['nout']].is_signed_by(cert_tx.outputs[certificate_claim['nout']])
|
||||||
|
return is_signed, certificate_claim['name']
|
||||||
|
return False, None
|
||||||
if not certificate_claim:
|
if not certificate_claim:
|
||||||
return False, None
|
return False, None
|
||||||
if 'value' not in certificate_claim:
|
if 'value' not in certificate_claim:
|
||||||
log.warning('Got an invalid claim while parsing certificates, please report: %s', certificate_claim)
|
log.warning('Got an invalid claim while parsing certificates, please report: %s', certificate_claim)
|
||||||
return False, None
|
return False, None
|
||||||
certificate = decoded_certificate or Claim.from_bytes(certificate_claim['value'])
|
certificate = decoded_certificate or certificate_claim['value']
|
||||||
if not isinstance(certificate, Claim):
|
if not isinstance(certificate, Claim):
|
||||||
raise TypeError("Certificate is not a ClaimDict: %s" % str(type(certificate)))
|
raise TypeError("Certificate is not a ClaimDict: %s" % str(type(certificate)))
|
||||||
if _validate_signed_claim(claim, claim_address, name, certificate):
|
if _validate_signed_claim(claim, claim_address, name, certificate):
|
||||||
|
|
|
@ -149,7 +149,7 @@ class LBRYBlockProcessor(BlockProcessor):
|
||||||
try:
|
try:
|
||||||
parse_lbry_uri(name.decode()) # skip invalid names
|
parse_lbry_uri(name.decode()) # skip invalid names
|
||||||
claim_dict = Claim.from_bytes(value)
|
claim_dict = Claim.from_bytes(value)
|
||||||
cert_id = unhexlify(claim_dict.signing_channel_id)[::-1]
|
cert_id = claim_dict.signing_channel_id
|
||||||
if not self.should_validate_signatures:
|
if not self.should_validate_signatures:
|
||||||
return cert_id
|
return cert_id
|
||||||
if cert_id:
|
if cert_id:
|
||||||
|
|
|
@ -114,7 +114,7 @@ class Output(BaseOutput):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def sign(self, channel: 'Output', first_input_id=None):
|
def sign(self, channel: 'Output', first_input_id=None):
|
||||||
self.claim.signing_channel_id = unhexlify(channel.claim_id)
|
self.claim.signing_channel_id = unhexlify(channel.claim_id)[::-1]
|
||||||
digest = sha256(b''.join([
|
digest = sha256(b''.join([
|
||||||
first_input_id or self.tx_ref.tx.inputs[0].txo_ref.id.encode(),
|
first_input_id or self.tx_ref.tx.inputs[0].txo_ref.id.encode(),
|
||||||
self.claim.signing_channel_id,
|
self.claim.signing_channel_id,
|
||||||
|
|
|
@ -109,7 +109,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
|
||||||
# After abandoning he just waits for his LBCs to be returned to his account
|
# After abandoning he just waits for his LBCs to be returned to his account
|
||||||
await self.generate(5)
|
await self.generate(5)
|
||||||
result = await self.daemon.jsonrpc_account_balance()
|
result = await self.daemon.jsonrpc_account_balance()
|
||||||
self.assertEqual(result, '8.9693585')
|
self.assertEqual(result, '8.969381')
|
||||||
|
|
||||||
# Amidst all this Chris receives a call from his friend Ramsey
|
# Amidst all this Chris receives a call from his friend Ramsey
|
||||||
# who says that it is of utmost urgency that Chris transfer him
|
# who says that it is of utmost urgency that Chris transfer him
|
||||||
|
@ -126,7 +126,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
|
||||||
await self.generate(5)
|
await self.generate(5)
|
||||||
result = await self.daemon.jsonrpc_account_balance()
|
result = await self.daemon.jsonrpc_account_balance()
|
||||||
# Chris' balance was correct
|
# Chris' balance was correct
|
||||||
self.assertEqual(result, '7.9692345')
|
self.assertEqual(result, '7.969257')
|
||||||
|
|
||||||
# Ramsey too assured him that he had received the 1 LBC and thanks him
|
# Ramsey too assured him that he had received the 1 LBC and thanks him
|
||||||
result = await self.daemon.jsonrpc_account_balance(ramsey_account_id)
|
result = await self.daemon.jsonrpc_account_balance(ramsey_account_id)
|
||||||
|
|
|
@ -62,7 +62,7 @@ class CommandTestCase(IntegrationTestCase):
|
||||||
timeout = 180
|
timeout = 180
|
||||||
LEDGER = lbrynet.wallet
|
LEDGER = lbrynet.wallet
|
||||||
MANAGER = LbryWalletManager
|
MANAGER = LbryWalletManager
|
||||||
VERBOSITY = logging.WARN
|
VERBOSITY = logging.DEBUG
|
||||||
|
|
||||||
async def asyncSetUp(self):
|
async def asyncSetUp(self):
|
||||||
await super().asyncSetUp()
|
await super().asyncSetUp()
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -9,7 +9,7 @@ extras = test
|
||||||
changedir = {toxinidir}/tests
|
changedir = {toxinidir}/tests
|
||||||
setenv =
|
setenv =
|
||||||
HOME=/tmp
|
HOME=/tmp
|
||||||
TORBA_LEDGER=lbrynet.extras.wallet
|
TORBA_LEDGER=lbrynet.wallet
|
||||||
commands =
|
commands =
|
||||||
orchstr8 download
|
orchstr8 download
|
||||||
coverage run -p --source={envsitepackagesdir}/lbrynet -m unittest discover -vv integration
|
coverage run -p --source={envsitepackagesdir}/lbrynet -m unittest discover -vv integration
|
||||||
|
|
Loading…
Reference in a new issue