mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-12 22:33:37 +08:00
509 lines
14 KiB
Python
509 lines
14 KiB
Python
#!/usr/bin/env python2
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Blockstack-client
|
|
~~~~~
|
|
copyright: (c) 2014-2015 by Halfmoon Labs, Inc.
|
|
copyright: (c) 2016 by Blockstack.org
|
|
|
|
This file is part of Blockstack-client.
|
|
|
|
Blockstack-client is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Blockstack-client is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
You should have received a copy of the GNU General Public License
|
|
along with Blockstack-client. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
from .config import LENGTHS, NAME_OPCODES, NAME_TRANSFER, TRANSFER_KEEP_DATA, TRANSFER_REMOVE_DATA, NAME_REGISTRATION
|
|
|
|
# schema constants
|
|
OP_HEX_PATTERN = r'^([0-9a-fA-F]+)$'
|
|
OP_CONSENSUS_HASH_PATTERN = r'^([0-9a-fA-F]{{{}}})$'.format(LENGTHS['consensus_hash'] * 2)
|
|
OP_ZONEFILE_HASH_PATTERN = r'^([0-9a-fA-F]{{{}}})$'.format(LENGTHS['value_hash'] * 2)
|
|
OP_BASE64_EMPTY_PATTERN = '^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$' # base64 with empty string
|
|
OP_BASE58CHECK_CLASS = r'[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]'
|
|
OP_BASE58CHECK_PATTERN = r'^({}+)$'.format(OP_BASE58CHECK_CLASS)
|
|
OP_ADDRESS_PATTERN = r'^({}{{1,35}})$'.format(OP_BASE58CHECK_CLASS)
|
|
OP_NAME_CHARS = r'a-z0-9\-_.+'
|
|
OP_NAME_CHARS_NOPERIOD = r'a-z0-9\-_+'
|
|
OP_NAME_CLASS = r'[{}]{{{},{}}}'.format(OP_NAME_CHARS, LENGTHS['fqn_min'], LENGTHS['fqn_max'])
|
|
OP_NAMESPACE_CLASS = r'[{}]{{{},{}}}'.format(OP_NAME_CHARS, 1, LENGTHS['namespace_id'])
|
|
OP_NAMESPACE_PATTERN = r'^({})$'.format(OP_NAMESPACE_CLASS)
|
|
OP_NAMESPACE_ID_HASH_PATTERN = r'^([0-9a-fA-F]{40})$'
|
|
OP_NAME_PATTERN = r'^({})$'.format(OP_NAME_CLASS)
|
|
OP_SUBDOMAIN_NAME_PATTERN = r'^([{}]+){{1,{}}}\.({})$'.format(OP_NAME_CHARS_NOPERIOD, LENGTHS['fqn_max'], OP_NAME_CLASS)
|
|
OP_NAME_OR_SUBDOMAIN_FRAGMENT = r'({})|({})'.format(OP_NAME_PATTERN, OP_SUBDOMAIN_NAME_PATTERN)
|
|
OP_NAME_OR_SUBDOMAIN_PATTERN = r'^{}$'.format(OP_NAME_OR_SUBDOMAIN_FRAGMENT)
|
|
OP_URI_TARGET_PATTERN = r'^([a-z0-9+]+)://([a-zA-Z0-9\-_.~%#?&\\:/=]+)$'
|
|
OP_URI_TARGET_PATTERN_NOSCHEME = r'^([a-zA-Z0-9\-_.~%#?&\\:/=]+)$'
|
|
OP_URLENCODED_CLASS = r'[a-zA-Z0-9\-_.~%/]'
|
|
OP_URLENCODED_PATTERN = r'^({}+)$'.format(OP_URLENCODED_CLASS)
|
|
OP_P2PKH_PATTERN = r'^76[aA]914[0-9a-fA-F]{40}88[aA][cC]$'
|
|
OP_SCRIPT_PATTERN = r'^[0-9a-fA-F]+$'
|
|
OP_CODE_PATTERN = r'^([{}]{{1}}|{}{}|{}{}|{}{})$'.format(
|
|
''.join(NAME_OPCODES.values()),
|
|
NAME_TRANSFER, TRANSFER_KEEP_DATA,
|
|
NAME_TRANSFER, TRANSFER_REMOVE_DATA,
|
|
NAME_REGISTRATION, NAME_REGISTRATION
|
|
)
|
|
OP_CODE_NAME_PATTERN = '|'.join(NAME_OPCODES.keys())
|
|
OP_HEX_PATTERN = r'^([0-9a-fA-F]+)$'
|
|
OP_PUBKEY_PATTERN = OP_HEX_PATTERN
|
|
OP_TXID_PATTERN = OP_HEX_PATTERN
|
|
|
|
URI_RECORD_SCHEMA = {
|
|
'type': 'object',
|
|
'properties': {
|
|
'name': {
|
|
'type': 'string'
|
|
},
|
|
'priority': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
'maximum': 65535,
|
|
},
|
|
'weight': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
'maximum': 65535,
|
|
},
|
|
'target': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_URI_TARGET_PATTERN,
|
|
},
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_URI_TARGET_PATTERN_NOSCHEME,
|
|
},
|
|
],
|
|
},
|
|
'class': {
|
|
'type': 'string'
|
|
},
|
|
'_missing_class': {
|
|
'type': 'boolean'
|
|
},
|
|
},
|
|
'required': [
|
|
'name',
|
|
'priority',
|
|
'weight',
|
|
'target'
|
|
],
|
|
}
|
|
|
|
TXT_RECORD_SCHEMA = {
|
|
'type': 'object',
|
|
'properties': {
|
|
'name': {
|
|
'type': 'string',
|
|
'pattern': OP_URLENCODED_PATTERN,
|
|
},
|
|
'txt': {
|
|
'type': ['string',
|
|
'array']
|
|
},
|
|
},
|
|
'required': [
|
|
'name',
|
|
'txt'
|
|
],
|
|
}
|
|
|
|
USER_ZONEFILE_SCHEMA = {
|
|
'type': 'object',
|
|
'properties': {
|
|
'txt': {
|
|
'type': 'array',
|
|
'items': TXT_RECORD_SCHEMA,
|
|
},
|
|
'uri': {
|
|
'type': 'array',
|
|
'items': URI_RECORD_SCHEMA,
|
|
},
|
|
'$origin': {
|
|
'type': 'string',
|
|
'pattern': OP_NAME_PATTERN,
|
|
},
|
|
'$ttl': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
'maximum': 2147483647,
|
|
},
|
|
},
|
|
'required': [
|
|
'$origin',
|
|
'$ttl'
|
|
],
|
|
}
|
|
|
|
|
|
OP_HISTORY_SCHEMA = {
|
|
'type': 'object',
|
|
'properties': {
|
|
'address': {
|
|
'type': 'string',
|
|
'pattern': OP_ADDRESS_PATTERN,
|
|
},
|
|
'base': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
'maximum': 255,
|
|
},
|
|
'buckets': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': r'^\[((0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15), ){15}(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15)\]$'
|
|
},
|
|
{
|
|
'type': 'array',
|
|
'items': {
|
|
'type': 'integer',
|
|
'minItems': 16,
|
|
'maxItems': 16,
|
|
},
|
|
},
|
|
{
|
|
'type': 'null',
|
|
},
|
|
],
|
|
},
|
|
'block_number': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'coeff': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
'maximum': 255,
|
|
},
|
|
{
|
|
'type': 'null'
|
|
},
|
|
],
|
|
},
|
|
'consensus_hash': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_CONSENSUS_HASH_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null'
|
|
},
|
|
],
|
|
},
|
|
'domain': {
|
|
'type': 'string',
|
|
'pattern': OP_NAME_PATTERN,
|
|
},
|
|
'fee': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'first_registered': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'history_snapshot': {
|
|
'type': 'boolean',
|
|
},
|
|
'importer': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_P2PKH_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null',
|
|
},
|
|
],
|
|
},
|
|
'importer_address': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_ADDRESS_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null',
|
|
},
|
|
],
|
|
},
|
|
'last_renewed': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'op': {
|
|
'type': 'string',
|
|
'pattern': OP_CODE_PATTERN,
|
|
},
|
|
'op_fee': {
|
|
'type': 'number',
|
|
},
|
|
'opcode': {
|
|
'type': 'string',
|
|
'pattern': OP_CODE_NAME_PATTERN,
|
|
},
|
|
'revoked': {
|
|
'type': 'boolean',
|
|
},
|
|
'sender': {
|
|
'type': 'string',
|
|
'pattern': OP_SCRIPT_PATTERN,
|
|
},
|
|
'sender_pubkey': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_PUBKEY_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null'
|
|
},
|
|
],
|
|
},
|
|
'sequence': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'recipient': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_SCRIPT_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null'
|
|
},
|
|
],
|
|
},
|
|
'recipient_address': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_ADDRESS_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null'
|
|
},
|
|
],
|
|
},
|
|
'recipient_pubkey': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_PUBKEY_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null'
|
|
},
|
|
],
|
|
},
|
|
'txid': {
|
|
'type': 'string',
|
|
'pattern': OP_TXID_PATTERN,
|
|
},
|
|
'value_hash': {
|
|
'anyOf': [
|
|
{
|
|
'type': 'string',
|
|
'pattern': OP_ZONEFILE_HASH_PATTERN,
|
|
},
|
|
{
|
|
'type': 'null',
|
|
},
|
|
],
|
|
},
|
|
'vtxindex': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'zonefile': {
|
|
'type': 'string',
|
|
'pattern': OP_BASE64_EMPTY_PATTERN,
|
|
},
|
|
},
|
|
'required': [
|
|
'op',
|
|
'opcode',
|
|
'txid',
|
|
'vtxindex'
|
|
],
|
|
}
|
|
|
|
NAMEOP_SCHEMA_PROPERTIES = {
|
|
'address': OP_HISTORY_SCHEMA['properties']['address'],
|
|
'block_number': OP_HISTORY_SCHEMA['properties']['block_number'],
|
|
'consensus_hash': OP_HISTORY_SCHEMA['properties']['consensus_hash'],
|
|
'domain': OP_HISTORY_SCHEMA['properties']['domain'],
|
|
'expired': {
|
|
# NOTE: filled in by the indexer
|
|
'type': 'boolean',
|
|
},
|
|
'expire_block': {
|
|
# NOTE: filled in by the indexer
|
|
'type': 'integer',
|
|
'minimum': -1,
|
|
},
|
|
'renewal_deadline': {
|
|
# NOTE: filled in by the indexer
|
|
'type': 'integer',
|
|
'minimum': -1,
|
|
},
|
|
'first_registered': OP_HISTORY_SCHEMA['properties']['first_registered'],
|
|
'history': {
|
|
'type': 'object',
|
|
'patternProperties': {
|
|
'^([0-9]+)$': {
|
|
'type': 'array',
|
|
'items': OP_HISTORY_SCHEMA,
|
|
},
|
|
},
|
|
},
|
|
'history_snapshot': {
|
|
'type': 'boolean',
|
|
},
|
|
'importer': OP_HISTORY_SCHEMA['properties']['importer'],
|
|
'importer_address': OP_HISTORY_SCHEMA['properties']['importer_address'],
|
|
'last_renewed': OP_HISTORY_SCHEMA['properties']['last_renewed'],
|
|
'name': {
|
|
'type': 'string',
|
|
'pattern': OP_NAME_PATTERN,
|
|
},
|
|
'op': OP_HISTORY_SCHEMA['properties']['op'],
|
|
'op_fee': OP_HISTORY_SCHEMA['properties']['op_fee'],
|
|
'opcode': OP_HISTORY_SCHEMA['properties']['opcode'],
|
|
'revoked': OP_HISTORY_SCHEMA['properties']['revoked'],
|
|
'sender': OP_HISTORY_SCHEMA['properties']['sender'],
|
|
'sender_pubkey': OP_HISTORY_SCHEMA['properties']['sender_pubkey'],
|
|
'sequence': OP_HISTORY_SCHEMA['properties']['sequence'],
|
|
'recipient': OP_HISTORY_SCHEMA['properties']['recipient'],
|
|
'recipient_address': OP_HISTORY_SCHEMA['properties']['recipient_address'],
|
|
'txid': OP_HISTORY_SCHEMA['properties']['txid'],
|
|
'value_hash': OP_HISTORY_SCHEMA['properties']['value_hash'],
|
|
'vtxindex': OP_HISTORY_SCHEMA['properties']['vtxindex'],
|
|
'zonefile': OP_HISTORY_SCHEMA['properties']['zonefile'],
|
|
}
|
|
|
|
NAMESPACE_SCHEMA_PROPERTIES = {
|
|
'address': OP_HISTORY_SCHEMA['properties']['address'],
|
|
'base': OP_HISTORY_SCHEMA['properties']['base'],
|
|
'block_number': OP_HISTORY_SCHEMA['properties']['block_number'],
|
|
'buckets': OP_HISTORY_SCHEMA['properties']['buckets'],
|
|
'coeff': OP_HISTORY_SCHEMA['properties']['coeff'],
|
|
'fee': OP_HISTORY_SCHEMA['properties']['fee'],
|
|
'history': {
|
|
'type': 'object',
|
|
'patternProperties': {
|
|
'^([0-9]+)$': {
|
|
'type': 'array',
|
|
'items': OP_HISTORY_SCHEMA,
|
|
},
|
|
},
|
|
},
|
|
'lifetime': {
|
|
'type': 'integer'
|
|
},
|
|
'namespace_id': {
|
|
'type': 'string',
|
|
'pattern': OP_NAMESPACE_PATTERN,
|
|
},
|
|
# legacy field
|
|
'namespace_id_hash': {
|
|
'type': 'string',
|
|
'pattern': OP_NAMESPACE_ID_HASH_PATTERN,
|
|
},
|
|
'no_vowel_discount': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
'maximum': 15,
|
|
},
|
|
'nonalpha_discount': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
'maximum': 15,
|
|
},
|
|
'op': OP_HISTORY_SCHEMA['properties']['op'],
|
|
'preorder_hash': {
|
|
'type': 'string',
|
|
'pattern': OP_NAMESPACE_ID_HASH_PATTERN,
|
|
},
|
|
'ready': {
|
|
'type': 'boolean',
|
|
},
|
|
'ready_block': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'recipient': OP_HISTORY_SCHEMA['properties']['recipient'],
|
|
'recipient_address': OP_HISTORY_SCHEMA['properties']['recipient_address'],
|
|
'reveal_block': {
|
|
'type': 'integer',
|
|
'minimum': 0,
|
|
},
|
|
'sender': OP_HISTORY_SCHEMA['properties']['sender'],
|
|
'sender_pubkey': OP_HISTORY_SCHEMA['properties']['sender_pubkey'],
|
|
'txid': OP_HISTORY_SCHEMA['properties']['txid'],
|
|
'version': {
|
|
'type': 'integer',
|
|
'minimum': 1,
|
|
},
|
|
'vtxindex': OP_HISTORY_SCHEMA['properties']['vtxindex'],
|
|
}
|
|
|
|
NAMEOP_SCHEMA_REQUIRED = [
|
|
'address',
|
|
'block_number',
|
|
'op',
|
|
'op_fee',
|
|
'opcode',
|
|
'sender',
|
|
'txid',
|
|
'vtxindex'
|
|
]
|
|
|
|
NAMESPACE_SCHEMA_REQUIRED = [
|
|
'address',
|
|
'base',
|
|
'block_number',
|
|
'buckets',
|
|
'coeff',
|
|
'lifetime',
|
|
'namespace_id',
|
|
'no_vowel_discount',
|
|
'nonalpha_discount',
|
|
'op',
|
|
'ready',
|
|
'recipient',
|
|
'recipient_address',
|
|
'reveal_block',
|
|
'sender',
|
|
'sender_pubkey',
|
|
'txid',
|
|
'version',
|
|
'vtxindex'
|
|
]
|
|
|
|
SUBDOMAIN_SCHEMA_REQUIRED = [
|
|
'address',
|
|
'domain',
|
|
'block_number',
|
|
'sequence',
|
|
'txid',
|
|
'value_hash',
|
|
]
|
|
|