from_dict() now also handles from_seed()

This commit is contained in:
Lex Berezhny 2018-08-06 02:52:52 -04:00
parent e996717b60
commit d4107600a5
4 changed files with 84 additions and 72 deletions

View file

@ -92,29 +92,35 @@ class TestHierarchicalDeterministicAccount(unittest.TestCase):
@defer.inlineCallbacks
def test_generate_account_from_seed(self):
account = self.ledger.account_class.from_seed(
self.ledger,
"carbon smart garage balance margin twelve chest sword toast envelope bottom stomach ab"
"sent", "torba", {'name': 'deterministic-chain', 'receiving_gap': 3, 'change_gap': 2}
account = self.ledger.account_class.from_dict(
self.ledger, {
"seed": "carbon smart garage balance margin twelve chest sword "
"toast envelope bottom stomach absent",
"address_generator": {
'name': 'deterministic-chain',
'receiving': {'gap': 3, 'maximum_uses_per_address': 1},
'change': {'gap': 2, 'maximum_uses_per_address': 1}
}
}
)
self.assertEqual(
account.private_key.extended_key_string(),
'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P'
'6yz3jMbycrLrRMpeAJxR8qDg8'
'xprv9s21ZrQH143K3TsAz5efNV8K93g3Ms3FXcjaWB9fVUsMwAoE3ZT4vYymkp5BxK'
'Kfnpz8J6sHDFriX1SnpvjNkzcks8XBnxjGLS83BTyfpna'
)
self.assertEqual(
account.public_key.extended_key_string(),
'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f'
'iW44g14WF52fYC5J483wqQ5ZP'
'xpub661MyMwAqRbcFwwe67Bfjd53h5WXmKm6tqfBJZZH3pQLoy8Nb6mKUMJFc7UbpV'
'NzmwFPN2evn3YHnig1pkKVYcvCV8owTd2yAcEkJfCX53g'
)
address = yield account.receiving.ensure_address_gap()
self.assertEqual(address[0], '1PmX9T3sCiDysNtWszJa44SkKcpGc2NaXP')
self.assertEqual(address[0], '1CDLuMfwmPqJiNk5C2Bvew6tpgjAGgUk8J')
private_key = yield self.ledger.get_private_key_for_address('1PmX9T3sCiDysNtWszJa44SkKcpGc2NaXP')
private_key = yield self.ledger.get_private_key_for_address('1CDLuMfwmPqJiNk5C2Bvew6tpgjAGgUk8J')
self.assertEqual(
private_key.extended_key_string(),
'xprv9xNEfQ296VTRaEUDZ8oKq74xw2U6kpj486vFUB4K1wT9U25GX4UwuzFgJN1YuRrqkQ5TTwCpkYnjNpSoH'
'SBaEigNHPkoeYbuPMRo6mRUjxg'
'xprv9xV7rhbg6M4yWrdTeLorz3Q1GrQb4aQzzGWboP3du7W7UUztzNTUrEYTnDfz7o'
'ptBygDxXYRppyiuenJpoBTgYP2C26E1Ah5FEALM24CsWi'
)
invalid_key = yield self.ledger.get_private_key_for_address('BcQjRlhDOIrQez1WHfz3whnB33Bp34sUgX')
@ -122,7 +128,7 @@ class TestHierarchicalDeterministicAccount(unittest.TestCase):
self.assertEqual(
hexlify(private_key.wif()),
b'1cc27be89ad47ef932562af80e95085eb0ab2ae3e5c019b1369b8b05ff2e94512f01'
b'1c01ae1e4c7d89e39f6d3aa7792c097a30ca7d40be249b6de52c81ec8cf9aab48b01'
)
@defer.inlineCallbacks
@ -134,11 +140,11 @@ class TestHierarchicalDeterministicAccount(unittest.TestCase):
"h absent",
'encrypted': False,
'private_key':
'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P'
'6yz3jMbycrLrRMpeAJxR8qDg8',
'xprv9s21ZrQH143K3TsAz5efNV8K93g3Ms3FXcjaWB9fVUsMwAoE3ZT4vYymkp'
'5BxKKfnpz8J6sHDFriX1SnpvjNkzcks8XBnxjGLS83BTyfpna',
'public_key':
'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f'
'iW44g14WF52fYC5J483wqQ5ZP',
'xpub661MyMwAqRbcFwwe67Bfjd53h5WXmKm6tqfBJZZH3pQLoy8Nb6mKUMJFc7'
'UbpVNzmwFPN2evn3YHnig1pkKVYcvCV8owTd2yAcEkJfCX53g',
'address_generator': {
'name': 'deterministic-chain',
'receiving': {'gap': 5, 'maximum_uses_per_address': 2},
@ -244,20 +250,23 @@ class TestSingleKeyAccount(unittest.TestCase):
@defer.inlineCallbacks
def test_generate_account_from_seed(self):
account = self.ledger.account_class.from_seed(
self.ledger,
"carbon smart garage balance margin twelve chest sword toast envelope bottom stomach ab"
"sent", "torba", {'name': 'single-address'}
account = self.ledger.account_class.from_dict(
self.ledger, {
"seed":
"carbon smart garage balance margin twelve chest sword toas"
"t envelope bottom stomach absent",
'address_generator': {'name': 'single-address'}
}
)
self.assertEqual(
account.private_key.extended_key_string(),
'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P'
'6yz3jMbycrLrRMpeAJxR8qDg8'
'xprv9s21ZrQH143K3TsAz5efNV8K93g3Ms3FXcjaWB9fVUsMwAoE3ZT4vYymkp'
'5BxKKfnpz8J6sHDFriX1SnpvjNkzcks8XBnxjGLS83BTyfpna',
)
self.assertEqual(
account.public_key.extended_key_string(),
'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f'
'iW44g14WF52fYC5J483wqQ5ZP'
'xpub661MyMwAqRbcFwwe67Bfjd53h5WXmKm6tqfBJZZH3pQLoy8Nb6mKUMJFc7'
'UbpVNzmwFPN2evn3YHnig1pkKVYcvCV8owTd2yAcEkJfCX53g',
)
address = yield account.receiving.ensure_address_gap()
self.assertEqual(address[0], account.public_key.address)
@ -265,8 +274,8 @@ class TestSingleKeyAccount(unittest.TestCase):
private_key = yield self.ledger.get_private_key_for_address(address[0])
self.assertEqual(
private_key.extended_key_string(),
'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P'
'6yz3jMbycrLrRMpeAJxR8qDg8'
'xprv9s21ZrQH143K3TsAz5efNV8K93g3Ms3FXcjaWB9fVUsMwAoE3ZT4vYymkp'
'5BxKKfnpz8J6sHDFriX1SnpvjNkzcks8XBnxjGLS83BTyfpna',
)
invalid_key = yield self.ledger.get_private_key_for_address('BcQjRlhDOIrQez1WHfz3whnB33Bp34sUgX')
@ -274,7 +283,7 @@ class TestSingleKeyAccount(unittest.TestCase):
self.assertEqual(
hexlify(private_key.wif()),
b'1c2423f3dc6087d9683f73a684935abc0ccd8bc26370588f56653128c6a6f0bf7c01'
b'1c92caa0ef99bfd5e2ceb73b66da8cd726a9370be8c368d448a322f3c5b23aaab901'
)
@defer.inlineCallbacks
@ -286,11 +295,11 @@ class TestSingleKeyAccount(unittest.TestCase):
"h absent",
'encrypted': False,
'private_key':
'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P'
'6yz3jMbycrLrRMpeAJxR8qDg8',
'xprv9s21ZrQH143K3TsAz5efNV8K93g3Ms3FXcjaWB9fVUsMwAoE3ZT4vYymkp'
'5BxKKfnpz8J6sHDFriX1SnpvjNkzcks8XBnxjGLS83BTyfpna',
'public_key':
'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f'
'iW44g14WF52fYC5J483wqQ5ZP',
'xpub661MyMwAqRbcFwwe67Bfjd53h5WXmKm6tqfBJZZH3pQLoy8Nb6mKUMJFc7'
'UbpVNzmwFPN2evn3YHnig1pkKVYcvCV8owTd2yAcEkJfCX53g',
'address_generator': {'name': 'single-address'}
}

View file

@ -141,10 +141,12 @@ class TestTransactionSigning(unittest.TestCase):
@defer.inlineCallbacks
def test_sign(self):
account = self.ledger.account_class.from_seed(
self.ledger,
u"carbon smart garage balance margin twelve chest sword toast envelope bottom stomach ab"
u"sent", u"torba", {}
account = self.ledger.account_class.from_dict(
self.ledger, {
"seed": "carbon smart garage balance margin twelve chest sword "
"toast envelope bottom stomach absent"
}
)
yield account.ensure_address_gap()
@ -160,10 +162,11 @@ class TestTransactionSigning(unittest.TestCase):
yield tx.sign([account])
print(hexlify(tx.inputs[0].script.values['signature']))
self.assertEqual(
hexlify(tx.inputs[0].script.values['signature']),
b'304402203d463519290d06891e461ea5256c56097ccdad53379b1bb4e51ec5abc6e9fd02022034ed15b9'
b'd7c678716c4aa7c0fd26c688e8f9db8075838f2839ab55d551b62c0a01'
b'304402205a1df8cd5d2d2fa5934b756883d6c07e4f83e1350c740992d47a12422'
b'226aaa202200098ac8675827aea2b0d6f0e49566143a95d523e311d342172cd99e2021e47cb01'
)
@ -173,10 +176,11 @@ class TransactionIOBalancing(unittest.TestCase):
def setUp(self):
self.ledger = ledger_class({'db': ledger_class.database_class(':memory:')})
yield self.ledger.db.start()
self.account = self.ledger.account_class.from_seed(
self.ledger,
u"carbon smart garage balance margin twelve chest sword toast envelope bottom stomach ab"
u"sent", u"torba", {}
self.account = self.ledger.account_class.from_dict(
self.ledger, {
"seed": "carbon smart garage balance margin twelve chest sword "
"toast envelope bottom stomach absent"
}
)
addresses = yield self.account.ensure_address_gap()

View file

@ -39,11 +39,11 @@ class TestWalletCreation(unittest.TestCase):
"h absent",
'encrypted': False,
'private_key':
'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P'
'6yz3jMbycrLrRMpeAJxR8qDg8',
'xprv9s21ZrQH143K3TsAz5efNV8K93g3Ms3FXcjaWB9fVUsMwAoE3Z'
'T4vYymkp5BxKKfnpz8J6sHDFriX1SnpvjNkzcks8XBnxjGLS83BTyfpna',
'public_key':
'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f'
'iW44g14WF52fYC5J483wqQ5ZP',
'xpub661MyMwAqRbcFwwe67Bfjd53h5WXmKm6tqfBJZZH3pQLoy8Nb6'
'mKUMJFc7UbpVNzmwFPN2evn3YHnig1pkKVYcvCV8owTd2yAcEkJfCX53g',
'address_generator': {
'name': 'deterministic-chain',
'receiving': {'gap': 17, 'maximum_uses_per_address': 3},

View file

@ -211,20 +211,12 @@ class BaseAccount:
ledger.add_account(self)
@classmethod
def generate(cls, ledger: 'baseledger.BaseLedger', password: str, address_generator: dict = None):
seed = cls.mnemonic_class().make_seed()
return cls.from_seed(ledger, seed, password, address_generator or {})
@classmethod
def from_seed(cls, ledger: 'baseledger.BaseLedger', seed: str, password: str, address_generator: dict):
private_key = cls.get_private_key_from_seed(ledger, seed, password)
return cls(
ledger=ledger, name='Account #{}'.format(private_key.public_key.address),
seed=seed, encrypted=False,
private_key=private_key,
public_key=private_key.public_key,
address_generator=address_generator
)
def generate(cls, ledger: 'baseledger.BaseLedger', name: str = None, address_generator: dict = None):
return cls.from_dict(ledger, {
'name': name,
'seed': cls.mnemonic_class().make_seed(),
'address_generator': address_generator or {}
})
@classmethod
def get_private_key_from_seed(cls, ledger: 'baseledger.BaseLedger', seed: str, password: str):
@ -234,23 +226,30 @@ class BaseAccount:
@classmethod
def from_dict(cls, ledger: 'baseledger.BaseLedger', d: dict):
if not d['private_key'] and not d['public_key'] and d['seed']:
private_key = cls.get_private_key_from_seed(ledger, d['seed'], '')
seed = d.get('seed', '')
private_key = d.get('private_key', '')
public_key = None
encrypted = d.get('encrypted', False)
if not encrypted:
if seed:
private_key = cls.get_private_key_from_seed(ledger, seed, '')
public_key = private_key.public_key
elif not d['encrypted'] and d['private_key']:
private_key = from_extended_key_string(ledger, d['private_key'])
elif private_key:
private_key = from_extended_key_string(ledger, private_key)
public_key = private_key.public_key
else:
private_key = d['private_key']
if public_key is None:
public_key = from_extended_key_string(ledger, d['public_key'])
name = d.get('name')
if not name:
name = 'Account #{}'.format(public_key.address)
return cls(
ledger=ledger,
name=d['name'],
seed=d['seed'],
encrypted=d['encrypted'],
name=name,
seed=seed,
encrypted=encrypted,
private_key=private_key,
public_key=public_key,
address_generator=d['address_generator']
address_generator=d.get('address_generator', {})
)
def to_dict(self):