wip4victor

This commit is contained in:
Lex Berezhny 2018-07-01 17:20:17 -04:00
parent c58a1c9ead
commit 6bb81e4d6f
6 changed files with 88 additions and 49 deletions

View file

@ -1,3 +1,4 @@
import asyncio
from orchstr8.testcase import IntegrationTestCase, d2f from orchstr8.testcase import IntegrationTestCase, d2f
from torba.constants import COIN from torba.constants import COIN
@ -12,13 +13,18 @@ class BasicTransactionTests(IntegrationTestCase):
self.assertEqual(await self.get_balance(account1), 0) self.assertEqual(await self.get_balance(account1), 0)
self.assertEqual(await self.get_balance(account2), 0) self.assertEqual(await self.get_balance(account2), 0)
sendtxids = []
for i in range(9):
address1 = await d2f(account1.receiving.get_or_create_usable_address()) address1 = await d2f(account1.receiving.get_or_create_usable_address())
sendtxid = await self.blockchain.send_to_address(address1.decode(), 5.5) sendtxid = await self.blockchain.send_to_address(address1.decode(), 1.1)
sendtxids.append(sendtxid)
await self.on_transaction_id(sendtxid) # mempool await self.on_transaction_id(sendtxid) # mempool
await self.blockchain.generate(1) await self.blockchain.generate(1)
await self.on_transaction_id(sendtxid) # confirmed await asyncio.wait([ # confirmed
self.on_transaction_id(txid) for txid in sendtxids
])
self.assertEqual(round(await self.get_balance(account1)/COIN, 1), 5.5) self.assertEqual(round(await self.get_balance(account1)/COIN, 1), 9.9)
self.assertEqual(round(await self.get_balance(account2)/COIN, 1), 0) self.assertEqual(round(await self.get_balance(account2)/COIN, 1), 0)
address2 = await d2f(account2.receiving.get_or_create_usable_address()) address2 = await d2f(account2.receiving.get_or_create_usable_address())
@ -32,7 +38,5 @@ class BasicTransactionTests(IntegrationTestCase):
await self.blockchain.generate(1) await self.blockchain.generate(1)
await self.on_transaction(tx) # confirmed await self.on_transaction(tx) # confirmed
self.assertTrue(await d2f(self.ledger.is_valid_transaction(tx, 202))) self.assertEqual(round(await self.get_balance(account1)/COIN, 1), 7.9)
self.assertEqual(round(await self.get_balance(account1)/COIN, 1), 3.5)
self.assertEqual(round(await self.get_balance(account2)/COIN, 1), 2.0) self.assertEqual(round(await self.get_balance(account2)/COIN, 1), 2.0)

View file

@ -34,7 +34,13 @@ class BaseHeaders:
@property @property
def height(self): def height(self):
return len(self) return len(self)-1
def hash(self, height=None):
if height is None:
height = self.height
header = self[height]
return self._hash_header(header)
def sync_read_length(self): def sync_read_length(self):
return os.path.getsize(self.path) // self.header_size return os.path.getsize(self.path) // self.header_size

View file

@ -203,7 +203,7 @@ class BaseLedger(six.with_metaclass(LedgerRegistry)):
def update_headers(self): def update_headers(self):
while True: while True:
height_sought = len(self.headers) height_sought = len(self.headers)
headers = yield self.network.get_headers(height_sought) headers = yield self.network.get_headers(height_sought, 2000)
if headers['count'] <= 0: if headers['count'] <= 0:
break break
yield self.headers.connect(height_sought, unhexlify(headers['hex'])) yield self.headers.connect(height_sought, unhexlify(headers['hex']))
@ -266,7 +266,7 @@ class BaseLedger(six.with_metaclass(LedgerRegistry)):
yield lock.acquire() yield lock.acquire()
try: #try:
# see if we have a local copy of transaction, otherwise fetch it from server # see if we have a local copy of transaction, otherwise fetch it from server
raw, local_height, is_verified = yield self.db.get_transaction(unhexlify(hex_id)[::-1]) raw, local_height, is_verified = yield self.db.get_transaction(unhexlify(hex_id)[::-1])
save_tx = None save_tx = None
@ -288,9 +288,16 @@ class BaseLedger(six.with_metaclass(LedgerRegistry)):
''.join('{}:{}:'.format(tx_id.decode(), tx_height) for tx_id, tx_height in synced_history) ''.join('{}:{}:'.format(tx_id.decode(), tx_height) for tx_id, tx_height in synced_history)
) )
log.debug("{}: sync'ed tx {} for address: {}, height: {}, verified: {}".format(
self.get_id(), hex_id, address, remote_height, is_verified
))
self._on_transaction_controller.add(TransactionEvent(address, tx, remote_height, is_verified)) self._on_transaction_controller.add(TransactionEvent(address, tx, remote_height, is_verified))
finally: # except:
# log.exception('Failed to synchronize transaction:')
# raise
#
# finally:
lock.release() lock.release()
if not lock.locked: if not lock.locked:
del self._transaction_processing_locks[hex_id] del self._transaction_processing_locks[hex_id]

View file

@ -11,7 +11,10 @@ from twisted.protocols.basic import LineOnlyReceiver
from torba import __version__ from torba import __version__
from torba.stream import StreamController from torba.stream import StreamController
log = logging.getLogger() log = logging.getLogger(__name__)
if six.PY3:
buffer = memoryview
def unicode2bytes(string): def unicode2bytes(string):
@ -23,6 +26,8 @@ def unicode2bytes(string):
def bytes2unicode(maybe_bytes): def bytes2unicode(maybe_bytes):
if isinstance(maybe_bytes, buffer):
maybe_bytes = str(maybe_bytes)
if isinstance(maybe_bytes, bytes): if isinstance(maybe_bytes, bytes):
return maybe_bytes.decode() return maybe_bytes.decode()
elif isinstance(maybe_bytes, (list, tuple)): elif isinstance(maybe_bytes, (list, tuple)):
@ -32,7 +37,7 @@ def bytes2unicode(maybe_bytes):
class StratumClientProtocol(LineOnlyReceiver): class StratumClientProtocol(LineOnlyReceiver):
delimiter = b'\n' delimiter = b'\n'
MAX_LENGTH = 100000 MAX_LENGTH = 2000000
def __init__(self): def __init__(self):
self.request_id = 0 self.request_id = 0
@ -78,6 +83,7 @@ class StratumClientProtocol(LineOnlyReceiver):
self.on_disconnected_controller.add(True) self.on_disconnected_controller.add(True)
def lineReceived(self, line): def lineReceived(self, line):
log.debug('received: {}'.format(line))
try: try:
# `line` comes in as a byte string but `json.loads` automatically converts everything to # `line` comes in as a byte string but `json.loads` automatically converts everything to
@ -114,6 +120,7 @@ class StratumClientProtocol(LineOnlyReceiver):
'method': method, 'method': method,
'params': [bytes2unicode(arg) for arg in args] 'params': [bytes2unicode(arg) for arg in args]
}) })
log.debug('sent: {}'.format(message))
self.sendLine(message.encode('latin-1')) self.sendLine(message.encode('latin-1'))
d = self.lookup_table[message_id] = defer.Deferred() d = self.lookup_table[message_id] = defer.Deferred()
return d return d
@ -161,17 +168,19 @@ class BaseNetwork:
def start(self): def start(self):
for server in cycle(self.config['default_servers']): for server in cycle(self.config['default_servers']):
endpoint = clientFromString(reactor, 'tcp:{}:{}'.format(*server)) endpoint = clientFromString(reactor, 'tcp:{}:{}'.format(*server))
log.debug("Attempting connection to SPV wallet server: {}:{}".format(*server))
self.service = ClientService(endpoint, StratumClientFactory(self)) self.service = ClientService(endpoint, StratumClientFactory(self))
self.service.startService() self.service.startService()
try: try:
self.client = yield self.service.whenConnected(failAfterFailures=2) self.client = yield self.service.whenConnected(failAfterFailures=2)
yield self.ensure_server_version() yield self.ensure_server_version()
log.info("Successfully connected to SPV wallet server: {}:{}".format(*server))
self._on_connected_controller.add(True) self._on_connected_controller.add(True)
yield self.client.on_disconnected.first yield self.client.on_disconnected.first
except CancelledError: except CancelledError:
return return
except Exception as e: except Exception:
pass log.exception("Connecting to {}:{} raised an exception:".format(*server))
finally: finally:
self.client = None self.client = None
if not self.running: if not self.running:

View file

@ -15,14 +15,13 @@ class WalletManager(object):
@classmethod @classmethod
def from_config(cls, config): # type: (Dict) -> WalletManager def from_config(cls, config): # type: (Dict) -> WalletManager
wallets = [] manager = cls()
manager = cls(wallets) for ledger_id, ledger_config in config.get('ledgers', {}).items():
for coin_id, ledger_config in config.get('ledgers', {}).items(): manager.get_or_create_ledger(ledger_id, ledger_config)
manager.get_or_create_ledger(coin_id, ledger_config)
for wallet_path in config.get('wallets', []): for wallet_path in config.get('wallets', []):
wallet_storage = WalletStorage(wallet_path) wallet_storage = WalletStorage(wallet_path)
wallet = Wallet.from_storage(wallet_storage, manager) wallet = Wallet.from_storage(wallet_storage, manager)
wallets.append(wallet) manager.wallets.append(wallet)
return manager return manager
def get_or_create_ledger(self, ledger_id, ledger_config=None): def get_or_create_ledger(self, ledger_id, ledger_config=None):

View file

@ -59,12 +59,11 @@ class Wallet:
class WalletStorage: class WalletStorage:
LATEST_VERSION = 2 LATEST_VERSION = 1
DEFAULT = { DEFAULT = {
'version': LATEST_VERSION, 'version': LATEST_VERSION,
'name': 'Wallet', 'name': 'Wallet',
'coins': {},
'accounts': [] 'accounts': []
} }
@ -100,10 +99,25 @@ class WalletStorage:
version = json_dict.pop('version', -1) version = json_dict.pop('version', -1)
if version == 1: # upgrade from version 1 to version 2 if version == -1: # upgrading from electrum wallet
_rename_property('addr_history', 'history') json_dict = {
_rename_property('use_encryption', 'encrypted') 'accounts': [{
_rename_property('gap_limit', 'gap_limit_for_receiving') 'ledger': 'lbc_mainnet',
'encrypted': json_dict['use_encryption'],
'seed': json_dict['seed'],
'seed_version': json_dict['seed_version'],
'private_key': json_dict['master_private_keys']['x/'],
'public_key': json_dict['master_public_keys']['x/'],
'certificates': json_dict['claim_certificates'],
'receiving_gap': 20,
'change_gap': 6,
'receiving_maximum_use_per_address': 2,
'change_maximum_use_per_address': 2
}]
}
elif version == 1: # upgrade from version 1 to version 2
pass
upgraded = cls.DEFAULT upgraded = cls.DEFAULT
upgraded.update(json_dict) upgraded.update(json_dict)