forked from LBRYCommunity/lbry-sdk
Add wallet json-schema, validate in one test.
This commit is contained in:
parent
d0c5b32a90
commit
eca69391ef
4 changed files with 207 additions and 0 deletions
|
@ -2,4 +2,5 @@ build:
|
|||
rm types/v2/* -rf
|
||||
touch types/v2/__init__.py
|
||||
cd types/v2/ && protoc --python_out=. -I ../../../../../types/v2/proto/ ../../../../../types/v2/proto/*.proto
|
||||
cd types/v2/ && cp ../../../../../types/jsonschema/* ./
|
||||
sed -e 's/^import\ \(.*\)_pb2\ /from . import\ \1_pb2\ /g' -i types/v2/*.py
|
||||
|
|
139
lbry/schema/types/v2/wallet.json
Normal file
139
lbry/schema/types/v2/wallet.json
Normal file
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"title": "Wallet",
|
||||
"description": "An LBC wallet",
|
||||
"type": "object",
|
||||
"required": ["name", "version", "accounts", "preferences"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Human readable name for this wallet",
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"description": "Wallet spec version",
|
||||
"type": "integer",
|
||||
"$comment": "Should this be a string? We may need some sort of decimal type if we want exact decimal versions."
|
||||
},
|
||||
"accounts": {
|
||||
"description": "Accounts associated with this wallet",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["address_generator", "certificates", "encrypted", "ledger", "modified_on", "name", "private_key", "public_key", "seed"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"address_generator": {
|
||||
"description": "Higher level manager of either singular or deterministically generated addresses",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"required": ["name", "change", "receiving"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "type of address generator: a deterministic chain of addresses",
|
||||
"enum": ["deterministic-chain"],
|
||||
"type": "string"
|
||||
},
|
||||
"change": {
|
||||
"$ref": "#/$defs/address_manager",
|
||||
"description": "Manager for deterministically generated change address (not used for single address)"
|
||||
},
|
||||
"receiving": {
|
||||
"$ref": "#/$defs/address_manager",
|
||||
"description": "Manager for deterministically generated receiving address (not used for single address)"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"required": ["name"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "type of address generator: a single address",
|
||||
"enum": ["single-address"],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"certificates": {
|
||||
"type": "object",
|
||||
"description": "Channel keys. Mapping from public key address to pem-formatted private key.",
|
||||
"additionalProperties": {"type": "string"}
|
||||
},
|
||||
"encrypted": {
|
||||
"type": "boolean",
|
||||
"description": "Whether private key and seed are encrypted with a password"
|
||||
},
|
||||
"ledger": {
|
||||
"description": "Which network to use",
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"lbc_mainnet",
|
||||
"lbc_testnet"
|
||||
]
|
||||
},
|
||||
"modified_on": {
|
||||
"description": "last modified time in Unix Time",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name for account, possibly human readable",
|
||||
"type": "string"
|
||||
},
|
||||
"private_key": {
|
||||
"description": "Private key for address if `address_generator` is a single address. Root of chain of private keys for addresses if `address_generator` is a deterministic chain of addresses. Encrypted if `encrypted` is true.",
|
||||
"type": "string"
|
||||
},
|
||||
"public_key": {
|
||||
"description": "Public key for address if `address_generator` is a single address. Root of chain of public keys for addresses if `address_generator` is a deterministic chain of addresses.",
|
||||
"type": "string"
|
||||
},
|
||||
"seed": {
|
||||
"description": "Human readable representation of `private_key`. encrypted if `encrypted` is set to `true`",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"preferences": {
|
||||
"description": "Timestamped application-level preferences. Values can be objects or of a primitive type.",
|
||||
"$comment": "enable-sync is seen in example wallet. encrypt-on-disk is seen in example wallet. they both have a boolean `value` field. Do we want them explicitly defined here? local and shared seem to have at least a similar structure (type, value [yes, again], version), value being the free-form part. Should we define those here? Or can there be any key under preferences, and `value` be literally be anything in any form?",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"required": ["ts", "value"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ts": {
|
||||
"type": "number",
|
||||
"description": "When the item was set, in Unix time format.",
|
||||
"$comment": "Do we want a string (decimal)?"
|
||||
},
|
||||
"value": {
|
||||
"$comment": "Sometimes this has been an object, sometimes just a boolean. I don't want to prescribe anything."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"address_manager": {
|
||||
"description": "Manager for deterministically generated addresses",
|
||||
"type": "object",
|
||||
"required": ["gap", "maximum_uses_per_address"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"gap": {
|
||||
"description": "Maximum allowed consecutive generated addresses with no transactions",
|
||||
"type": "integer"
|
||||
},
|
||||
"maximum_uses_per_address": {
|
||||
"description": "Maximum number of uses for each generated address",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
setup.py
1
setup.py
|
@ -53,6 +53,7 @@ setup(
|
|||
'multidict==4.6.1',
|
||||
'coincurve==15.0.0',
|
||||
'pbkdf2==1.3',
|
||||
'jsonschema==4.4.0',
|
||||
'attrs==18.2.0',
|
||||
'pylru==1.1.0',
|
||||
'elasticsearch==7.10.1',
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import json
|
||||
import jsonschema
|
||||
import os
|
||||
import pathlib
|
||||
import tempfile
|
||||
from binascii import hexlify
|
||||
|
||||
|
@ -17,6 +21,12 @@ class TestWalletCreation(AsyncioTestCase):
|
|||
self.main_ledger = self.manager.get_or_create_ledger(Ledger.get_id(), config)
|
||||
self.test_ledger = self.manager.get_or_create_ledger(RegTestLedger.get_id(), config)
|
||||
|
||||
base_dir = pathlib.Path(__file__).parents[3]
|
||||
types_dir = base_dir.joinpath('lbry', 'schema', 'types', 'v2')
|
||||
|
||||
with types_dir.joinpath('wallet.json').open() as f:
|
||||
self.wallet_schema = json.load(f)
|
||||
|
||||
def test_create_wallet_and_accounts(self):
|
||||
wallet = Wallet()
|
||||
self.assertEqual(wallet.name, 'Wallet')
|
||||
|
@ -74,6 +84,62 @@ class TestWalletCreation(AsyncioTestCase):
|
|||
decrypted = Wallet.unpack('password', encrypted)
|
||||
self.assertEqual(decrypted['accounts'][0]['name'], 'An Account')
|
||||
|
||||
|
||||
def test_wallet_file_schema(self):
|
||||
# One Deterministic Chain, one Single Address, to test both paths in the schema.
|
||||
wallet_dict = {
|
||||
'version': 1,
|
||||
'name': 'Main Wallet',
|
||||
'preferences': {},
|
||||
'accounts': [
|
||||
{
|
||||
'certificates': {'x': 'y'},
|
||||
'name': 'Account 1',
|
||||
'ledger': 'lbc_mainnet',
|
||||
'modified_on': 123,
|
||||
'seed':
|
||||
"carbon smart garage balance margin twelve chest sword toast envelope bottom stomac"
|
||||
"h absent",
|
||||
'encrypted': False,
|
||||
'private_key':
|
||||
'xprv9s21ZrQH143K42ovpZygnjfHdAqSd9jo7zceDfPRogM7bkkoNVv7'
|
||||
'DRNLEoB8HoirMgH969NrgL8jNzLEegqFzPRWM37GXd4uE8uuRkx4LAe',
|
||||
'public_key':
|
||||
'xpub661MyMwAqRbcGWtPvbWh9sc2BCfw2cTeVDYF23o3N1t6UZ5wv3EMm'
|
||||
'Dgp66FxHuDtWdft3B5eL5xQtyzAtkdmhhC95gjRjLzSTdkho95asu9',
|
||||
'address_generator': {
|
||||
'name': 'deterministic-chain',
|
||||
'receiving': {'gap': 17, 'maximum_uses_per_address': 3},
|
||||
'change': {'gap': 10, 'maximum_uses_per_address': 3}
|
||||
}
|
||||
},
|
||||
{
|
||||
'certificates': {'a': 'b'},
|
||||
'name': 'Account 2',
|
||||
'ledger': 'lbc_mainnet',
|
||||
'modified_on': 123,
|
||||
'seed':
|
||||
"carbon smart garage balance margin twelve chest sword toast envelope bottom stomac"
|
||||
"h absent",
|
||||
'encrypted': True,
|
||||
'private_key':
|
||||
'xprv9s21ZrQH143K42ovpZygnjfHdAqSd9jo7zceDfPRogM7bkkoNVv7'
|
||||
'DRNLEoB8HoirMgH969NrgL8jNzLEegqFzPRWM37GXd4uE8uuRkx4LAe',
|
||||
'public_key':
|
||||
'xpub661MyMwAqRbcGWtPvbWh9sc2BCfw2cTeVDYF23o3N1t6UZ5wv3EMm'
|
||||
'Dgp66FxHuDtWdft3B5eL5xQtyzAtkdmhhC95gjRjLzSTdkho95asu9',
|
||||
'address_generator': {
|
||||
'name': 'single-address',
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
storage = WalletStorage(default=wallet_dict)
|
||||
wallet = Wallet.from_storage(storage, self.manager)
|
||||
self.assertDictEqual(wallet_dict, wallet.to_dict())
|
||||
jsonschema.validate(schema=self.wallet_schema, instance=wallet.to_dict())
|
||||
|
||||
def test_no_password_but_encryption_preferred(self):
|
||||
wallet_dict = {
|
||||
'version': 1,
|
||||
|
|
Loading…
Reference in a new issue