forked from LBRYCommunity/lbry-sdk
from_dict() now also handles from_seed()
This commit is contained in:
parent
e996717b60
commit
d4107600a5
4 changed files with 84 additions and 72 deletions
|
@ -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'}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Add table
Reference in a new issue