jsonrpc_channel_new uses new wallet

This commit is contained in:
Lex Berezhny 2018-07-04 22:16:02 -04:00 committed by Jack Robison
parent cc970c499b
commit d5beaa0937
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2
5 changed files with 114 additions and 71 deletions

View file

@ -1,5 +1,3 @@
# coding=utf-8
import binascii
import logging.handlers
import mimetypes
import os
@ -7,6 +5,9 @@ import requests
import urllib
import json
import textwrap
import signal
import six
from binascii import hexlify, unhexlify, b2a_hex
from copy import deepcopy
from decimal import Decimal, InvalidOperation
from twisted.web import server
@ -14,6 +15,8 @@ from twisted.internet import defer, reactor
from twisted.internet.task import LoopingCall
from twisted.python.failure import Failure
from torba.constants import COIN
import lbryschema
from lbryschema.claim import ClaimDict
from lbryschema.uri import parse_lbry_uri
@ -231,6 +234,10 @@ class Daemon(AuthJSONRPCServer):
# TODO: delete this
self.streams = {}
@property
def ledger(self):
return self.session.wallet.default_account.ledger
@defer.inlineCallbacks
def setup(self):
log.info("Starting lbrynet-daemon")
@ -511,7 +518,7 @@ class Daemon(AuthJSONRPCServer):
@defer.inlineCallbacks
def _get_lbry_file_dict(self, lbry_file, full_status=False):
key = binascii.b2a_hex(lbry_file.key) if lbry_file.key else None
key = b2a_hex(lbry_file.key) if lbry_file.key else None
full_path = os.path.join(lbry_file.download_directory, lbry_file.file_name)
mime_type = mimetypes.guess_type(full_path)[0]
if os.path.isfile(full_path):
@ -1532,38 +1539,21 @@ class Daemon(AuthJSONRPCServer):
'claim_id' : (str) claim ID of the resulting claim
}
"""
try:
parsed = parse_lbry_uri(channel_name)
if not parsed.is_channel:
raise Exception("Cannot make a new channel for a non channel name")
if parsed.path:
raise Exception("Invalid channel uri")
except (TypeError, URIParseError):
raise Exception("Invalid channel name")
if amount <= 0:
raise Exception("Invalid amount")
yield self.wallet.update_balance()
if amount >= self.wallet.get_balance():
balance = yield self.wallet.get_max_usable_balance_for_claim(channel_name)
max_bid_amount = balance - MAX_UPDATE_FEE_ESTIMATE
if balance <= MAX_UPDATE_FEE_ESTIMATE:
raise InsufficientFundsError(
"Insufficient funds, please deposit additional LBC. Minimum additional LBC needed {}"
.format(MAX_UPDATE_FEE_ESTIMATE - balance))
elif amount > max_bid_amount:
raise InsufficientFundsError(
"Please wait for any pending bids to resolve or lower the bid value. "
"Currently the maximum amount you can specify for this channel is {}"
.format(max_bid_amount)
)
result = yield self.wallet.claim_new_channel(channel_name, amount)
tx = yield self.wallet.claim_new_channel(channel_name, amount)
script = tx.outputs[0].script
result = {
"success": True,
"txid": tx.hex_id.decode(),
"nout": 0,
"tx": hexlify(tx.raw),
"fee": str(Decimal(tx.fee) / COIN),
"claim_id": tx.get_claim_id(0),
"value": hexlify(script.values['claim']),
"claim_address": self.ledger.hash160_to_address(script.values['pubkey_hash'])
}
self.analytics_manager.send_new_channel()
log.info("Claimed a new channel! Result: %s", result)
response = yield self._render_response(result)
defer.returnValue(response)
defer.returnValue(result)
@requires(WALLET_COMPONENT)
@defer.inlineCallbacks
@ -2628,7 +2618,7 @@ class Daemon(AuthJSONRPCServer):
if not utils.is_valid_blobhash(blob_hash):
raise Exception("invalid blob hash")
finished_deferred = self.dht_node.iterativeFindValue(binascii.unhexlify(blob_hash))
finished_deferred = self.dht_node.iterativeFindValue(unhexlify(blob_hash))
def trap_timeout(err):
err.trap(defer.TimeoutError)

View file

@ -0,0 +1,56 @@
import types
from orchstr8.testcase import IntegrationTestCase, d2f
from torba.constants import COIN
import lbryschema
lbryschema.BLOCKCHAIN_NAME = 'lbrycrd_regtest'
from lbrynet import conf as lbry_conf
from lbrynet.daemon.Daemon import Daemon
from lbrynet.wallet.manager import LbryWalletManager
class FakeAnalytics:
def send_new_channel(self):
pass
class CommandTestCase(IntegrationTestCase):
WALLET_MANAGER = LbryWalletManager
async def setUp(self):
await super().setUp()
lbry_conf.settings = None
lbry_conf.initialize_settings(load_conf_file=False)
lbry_conf.settings['data_dir'] = self.stack.wallet.data_path
lbry_conf.settings['lbryum_wallet_dir'] = self.stack.wallet.data_path
lbry_conf.settings['download_directory'] = self.stack.wallet.data_path
lbry_conf.settings['use_upnp'] = False
lbry_conf.settings['blockchain_name'] = 'lbrycrd_regtest'
lbry_conf.settings['lbryum_servers'] = [('localhost', 50001)]
lbry_conf.settings['known_dht_nodes'] = []
lbry_conf.settings.node_id = None
await d2f(self.account.ensure_address_gap())
address = (await d2f(self.account.receiving.get_usable_addresses(1)))[0]
sendtxid = await self.blockchain.send_to_address(address.decode(), 10)
await self.on_transaction_id(sendtxid)
await self.blockchain.generate(1)
await self.on_transaction_id(sendtxid)
self.daemon = Daemon(FakeAnalytics())
self.daemon.session = types.SimpleNamespace()
self.daemon.session.wallet = self.manager
class DaemonCommandsTests(CommandTestCase):
VERBOSE = True
async def test_new_channel(self):
result = await d2f(self.daemon.jsonrpc_channel_new('@bar', 1*COIN))
self.assertIn('txid', result)
await self.on_transaction_id(result['txid'])

View file

@ -13,5 +13,12 @@ def generate_certificate():
class Account(BaseAccount):
def __init__(self, *args, **kwargs):
super(BaseAccount, self).__init__(*args, **kwargs)
super(Account, self).__init__(*args, **kwargs)
self.certificates = {}
def add_certificate(self, claim_id, key):
assert claim_id not in self.certificates, 'Trying to add a duplicate certificate.'
self.certificates[claim_id] = key
def get_certificate(self, claim_id):
return self.certificates[claim_id]

View file

@ -6,6 +6,7 @@ from torba.baseledger import BaseLedger
from torba.baseheader import BaseHeaders, _ArithUint256
from torba.util import int_to_hex, rev_hex, hash_encode
from .account import Account
from .network import Network
from .database import WalletDatabase
from .transaction import Transaction
@ -88,6 +89,7 @@ class MainNetLedger(BaseLedger):
symbol = 'LBC'
network_name = 'mainnet'
account_class = Account
database_class = WalletDatabase
headers_class = Headers
network_class = Network

View file

@ -6,8 +6,12 @@ from torba.constants import COIN
from torba.coinselection import CoinSelector
from torba.manager import WalletManager as BaseWalletManager
from lbryschema.uri import parse_lbry_uri
from lbryschema.error import URIParseError
from .ledger import MainNetLedger
from .account import generate_certificate
from .transaction import Transaction
class BackwardsCompatibleNetwork:
@ -101,44 +105,28 @@ class LbryWalletManager(BaseWalletManager):
return defer.succeed([])
def claim_name(self, name, amount, claim):
amount = int(amount * COIN)
pass
@defer.inlineCallbacks
def claim_new_channel(self, channel_name, amount):
try:
parsed = parse_lbry_uri(channel_name)
if not parsed.is_channel:
raise Exception("Cannot make a new channel for a non channel name")
if parsed.path:
raise Exception("Invalid channel uri")
except (TypeError, URIParseError):
raise Exception("Invalid channel name")
if amount <= 0:
raise Exception("Invalid amount")
account = self.default_account
coin = account.coin
ledger = coin.ledger
estimators = [
txo.get_estimator(coin) for txo in ledger.get_unspent_outputs()
]
cost_of_output = coin.get_input_output_fee(
Output.pay_pubkey_hash(COIN, NULL_HASH)
)
selector = CoinSelector(estimators, amount, cost_of_output)
spendables = selector.select()
if not spendables:
raise ValueError('Not enough funds to cover this transaction.')
claim_address = account.get_least_used_receiving_address()
outputs = [
Output.pay_claim_name_pubkey_hash(
amount, name, claim, coin.address_to_hash160(claim_address)
)
]
spent_sum = sum(s.effective_amount for s in spendables)
if spent_sum > amount:
change_address = account.get_least_used_change_address()
change_hash160 = coin.address_to_hash160(change_address)
outputs.append(Output.pay_pubkey_hash(spent_sum - amount, change_hash160))
tx = Transaction() \
.add_inputs([s.txi for s in spendables]) \
.add_outputs(outputs) \
.sign(account)
return tx
address = yield account.receiving.get_or_create_usable_address()
cert, key = generate_certificate()
tx = yield Transaction.claim(channel_name.encode(), cert, amount, address, [account], account)
yield account.ledger.broadcast(tx)
account.add_certificate(tx.get_claim_id(0), key)
# TODO: release reserved tx outputs in case anything fails by this point
defer.returnValue(tx)
class ReservedPoints: