diff --git a/lbrynet/extras/daemon/json_response_encoder.py b/lbrynet/extras/daemon/json_response_encoder.py index 6dd44bfd4..c7ae5e23c 100644 --- a/lbrynet/extras/daemon/json_response_encoder.py +++ b/lbrynet/extras/daemon/json_response_encoder.py @@ -77,6 +77,7 @@ class JSONResponseEncoder(JSONEncoder): if txo.channel is not None: output['channel_name'] = txo.channel.claim_name try: + raise ValueError() output['valid_signature'] = txo.is_signed_by(txo.channel, self.ledger) except BadSignatureError: output['valid_signature'] = False diff --git a/lbrynet/schema/base.py b/lbrynet/schema/base.py index 6cc7564cc..974a819df 100644 --- a/lbrynet/schema/base.py +++ b/lbrynet/schema/base.py @@ -1,3 +1,5 @@ +from binascii import hexlify + from google.protobuf.message import DecodeError from google.protobuf.json_format import MessageToDict @@ -23,6 +25,10 @@ class Signable: def is_undetermined(self): 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 def is_signed(self): return self.signature is not None diff --git a/lbrynet/wallet/database.py b/lbrynet/wallet/database.py index 585f7b045..3b2568c46 100644 --- a/lbrynet/wallet/database.py +++ b/lbrynet/wallet/database.py @@ -1,3 +1,5 @@ +from binascii import hexlify + from torba.client.basedatabase import BaseDatabase @@ -57,7 +59,7 @@ class WalletDatabase(BaseDatabase): for txo in txos: if txo.script.is_claim_name or txo.script.is_update_claim: 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: txo.private_key = my_account.get_certificate_private_key(txo.ref) @@ -71,8 +73,7 @@ class WalletDatabase(BaseDatabase): } for txo in txos: if txo.script.is_claim_name or txo.script.is_update_claim: - if 'publisherSignature' in txo.claim_dict: - txo.channel = channels.get(txo.claim_dict['publisherSignature']['certificateId']) + txo.channel = channels.get(txo.claim.signing_channel_hash, None) return txos diff --git a/lbrynet/wallet/ledger.py b/lbrynet/wallet/ledger.py index d930ef4eb..c7bf1f5af 100644 --- a/lbrynet/wallet/ledger.py +++ b/lbrynet/wallet/ledger.py @@ -67,6 +67,7 @@ class MainNetLedger(BaseLedger): resolutions = await self.network.get_values_for_uris(self.headers.hash().decode(), *uris) return await resolver._handle_resolutions(resolutions, uris, page, page_size) except Exception as e: + log.exception(e) return {'error': str(e)} async def get_claim_by_claim_id(self, claim_id): diff --git a/lbrynet/wallet/manager.py b/lbrynet/wallet/manager.py index f21619ee9..7cbbc425b 100644 --- a/lbrynet/wallet/manager.py +++ b/lbrynet/wallet/manager.py @@ -416,12 +416,13 @@ class LbryWalletManager(BaseWalletManager): if certificate: claim_output.sign(certificate, first_input_id=b'placeholder') + claim_output.script.generate() tx = await Transaction.create(inputs, [claim_output], [account], account) if certificate: claim_output.sign(certificate) - tx._reset() + await tx.sign([account]) await account.ledger.broadcast(tx) 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) ) key = claim_output.generate_channel_private_key() + claim_output.script.generate() tx = await Transaction.create([], [claim_output], [account], account) + await account.ledger.broadcast(tx) account.add_certificate_private_key(tx.outputs[0].ref, key.decode()) # TODO: release reserved tx outputs in case anything fails by this point diff --git a/lbrynet/wallet/resolve.py b/lbrynet/wallet/resolve.py index 3b3fbe5fc..17272d922 100644 --- a/lbrynet/wallet/resolve.py +++ b/lbrynet/wallet/resolve.py @@ -8,6 +8,8 @@ from lbrynet.schema.claim import Claim from google.protobuf.message import DecodeError from lbrynet.schema.uri import parse_lbry_uri from lbrynet.wallet.claim_proofs import verify_proof, InvalidProofError +from lbrynet.wallet.transaction import Transaction + log = logging.getLogger(__name__) @@ -30,6 +32,7 @@ class Resolver: await self._handle_resolve_uri_response(uri, resolution, page, page_size) ) except (UnknownNameError, UnknownClaimID, UnknownURI) as err: + log.exception(err) results[uri] = {'error': str(err)} else: 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: return claim_result 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: + certificate_id = hexlify(certificate_id[::-1]).decode() certificate = await self.network.get_claims_by_ids(certificate_id) certificate = certificate.pop(certificate_id) if certificate else None return await self.parse_and_validate_claim_result(claim_result, certificate=certificate) @@ -175,6 +179,8 @@ class Resolver: if decoded: claim_result['has_signature'] = False 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: log.info("fetching certificate to check claim signature") 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['signature_is_valid'] = False 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 if validated: 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"} -def validate_claim_signature_and_get_channel_name(claim, certificate_claim, - claim_address, name, decoded_certificate=None): +def validate_claim_signature_and_get_channel_name(claim_result, certificate_claim, + 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: return False, None if 'value' not in certificate_claim: log.warning('Got an invalid claim while parsing certificates, please report: %s', certificate_claim) 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): raise TypeError("Certificate is not a ClaimDict: %s" % str(type(certificate))) if _validate_signed_claim(claim, claim_address, name, certificate): diff --git a/lbrynet/wallet/server/block_processor.py b/lbrynet/wallet/server/block_processor.py index 029bc3cee..9c89cb0a5 100644 --- a/lbrynet/wallet/server/block_processor.py +++ b/lbrynet/wallet/server/block_processor.py @@ -149,7 +149,7 @@ class LBRYBlockProcessor(BlockProcessor): try: parse_lbry_uri(name.decode()) # skip invalid names 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: return cert_id if cert_id: diff --git a/lbrynet/wallet/transaction.py b/lbrynet/wallet/transaction.py index eb037567f..29e206c5e 100644 --- a/lbrynet/wallet/transaction.py +++ b/lbrynet/wallet/transaction.py @@ -114,7 +114,7 @@ class Output(BaseOutput): return True 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([ first_input_id or self.tx_ref.tx.inputs[0].txo_ref.id.encode(), self.claim.signing_channel_id, diff --git a/tests/integration/test_chris45.py b/tests/integration/test_chris45.py index 0a71c391f..dd4c9fe3d 100644 --- a/tests/integration/test_chris45.py +++ b/tests/integration/test_chris45.py @@ -109,7 +109,7 @@ class EpicAdventuresOfChris45(CommandTestCase): # After abandoning he just waits for his LBCs to be returned to his account await self.generate(5) 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 # who says that it is of utmost urgency that Chris transfer him @@ -126,7 +126,7 @@ class EpicAdventuresOfChris45(CommandTestCase): await self.generate(5) result = await self.daemon.jsonrpc_account_balance() # 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 result = await self.daemon.jsonrpc_account_balance(ramsey_account_id) diff --git a/tests/integration/testcase.py b/tests/integration/testcase.py index 84abf8e32..75ce9c284 100644 --- a/tests/integration/testcase.py +++ b/tests/integration/testcase.py @@ -62,7 +62,7 @@ class CommandTestCase(IntegrationTestCase): timeout = 180 LEDGER = lbrynet.wallet MANAGER = LbryWalletManager - VERBOSITY = logging.WARN + VERBOSITY = logging.DEBUG async def asyncSetUp(self): await super().asyncSetUp() diff --git a/tox.ini b/tox.ini index e3b237816..d66c1b87b 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ extras = test changedir = {toxinidir}/tests setenv = HOME=/tmp - TORBA_LEDGER=lbrynet.extras.wallet + TORBA_LEDGER=lbrynet.wallet commands = orchstr8 download coverage run -p --source={envsitepackagesdir}/lbrynet -m unittest discover -vv integration