jsonrpc_channel_new uses new wallet
This commit is contained in:
parent
cc970c499b
commit
d5beaa0937
5 changed files with 114 additions and 71 deletions
|
@ -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)
|
||||
|
|
56
lbrynet/tests/integration/wallet/test_commands.py
Normal file
56
lbrynet/tests/integration/wallet/test_commands.py
Normal 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'])
|
||||
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue