wip4victor
This commit is contained in:
parent
c58a1c9ead
commit
6bb81e4d6f
6 changed files with 88 additions and 49 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue