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

View file

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

View file

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

View file

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