Skip to content

Commit

Permalink
restructure coins.py
Browse files Browse the repository at this point in the history
  • Loading branch information
jakesum committed May 5, 2020
1 parent c590d60 commit 89d1bcd
Show file tree
Hide file tree
Showing 19 changed files with 4,189 additions and 2 deletions.
5 changes: 5 additions & 0 deletions contrib/daemontools/run 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
echo "Launching ElectrumX server..."
USERNAME=$(envdir ./env printenv USERNAME)
ELECTRUMX=$(envdir ./env printenv ELECTRUMX)
ulimit -n 4000 && exec 2>&1 envdir ./env envuidgid $USERNAME python3 $ELECTRUMX
4 changes: 2 additions & 2 deletions docs/rpc-interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ A typical result is as follows (with annotated comments)::

$ electrumx_rpc getinfo
{
"coin": "BitcoinSegwit",
"daemon": "127.0.0.1:9334/",
"coin": "Sumcoin",
"daemon": "127.0.0.1:3332/",
"daemon height": 572154, # The daemon's height when last queried
"db height": 572154, # The height to which the DB is flushed
"groups": 586, # The number of session groups
Expand Down
54 changes: 54 additions & 0 deletions electrumx/lib/enum 2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright (c) 2016, Neil Booth
#
# All rights reserved.
#
# See the file "LICENCE" for information about the copyright
# and warranty status of this software.

'''An enum-like type with reverse lookup.
Source: Python Cookbook, http://code.activestate.com/recipes/67107/
'''


class EnumError(Exception):
pass


class Enumeration:

def __init__(self, name, enumList):
self.__doc__ = name

lookup = {}
reverseLookup = {}
i = 0
uniqueNames = set()
uniqueValues = set()
for x in enumList:
if isinstance(x, tuple):
x, i = x
if not isinstance(x, str):
raise EnumError("enum name {} not a string".format(x))
if not isinstance(i, int):
raise EnumError("enum value {} not an integer".format(i))
if x in uniqueNames:
raise EnumError("enum name {} not unique".format(x))
if i in uniqueValues:
raise EnumError("enum value {} not unique".format(x))
uniqueNames.add(x)
uniqueValues.add(i)
lookup[x] = i
reverseLookup[i] = x
i = i + 1
self.lookup = lookup
self.reverseLookup = reverseLookup

def __getattr__(self, attr):
result = self.lookup.get(attr)
if result is None:
raise AttributeError('enumeration has no member {}'.format(attr))
return result

def whatis(self, value):
return self.reverseLookup[value]
79 changes: 79 additions & 0 deletions electrumx/lib/env_base 2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright (c) 2017, Neil Booth
#
# All rights reserved.
#
# See the file "LICENCE" for information about the copyright
# and warranty status of this software.

'''Class for server environment configuration and defaults.'''


from os import environ

from electrumx.lib.util import class_logger


class EnvBase(object):
'''Wraps environment configuration.'''

class Error(Exception):
pass

def __init__(self):
self.logger = class_logger(__name__, self.__class__.__name__)
self.allow_root = self.boolean('ALLOW_ROOT', False)
self.loop_policy = self.event_loop_policy()

@classmethod
def default(cls, envvar, default):
return environ.get(envvar, default)

@classmethod
def boolean(cls, envvar, default):
default = 'Yes' if default else ''
return bool(cls.default(envvar, default).strip())

@classmethod
def required(cls, envvar):
value = environ.get(envvar)
if value is None:
raise cls.Error('required envvar {} not set'.format(envvar))
return value

@classmethod
def integer(cls, envvar, default):
value = environ.get(envvar)
if value is None:
return default
try:
return int(value)
except Exception:
raise cls.Error('cannot convert envvar {} value {} to an integer'
.format(envvar, value))

@classmethod
def custom(cls, envvar, default, parse):
value = environ.get(envvar)
if value is None:
return default
try:
return parse(value)
except Exception as e:
raise cls.Error('cannot parse envvar {} value {}'
.format(envvar, value)) from e

@classmethod
def obsolete(cls, envvars):
bad = [envvar for envvar in envvars if environ.get(envvar)]
if bad:
raise cls.Error('remove obsolete environment variables {}'
.format(bad))

def event_loop_policy(self):
policy = self.default('EVENT_LOOP_POLICY', None)
if policy is None:
return None
if policy == 'uvloop':
import uvloop
return uvloop.EventLoopPolicy()
raise self.Error('unknown event loop policy "{}"'.format(policy))
159 changes: 159 additions & 0 deletions electrumx/lib/hash 2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Copyright (c) 2016-2017, Neil Booth
#
# All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

'''Cryptograph hash functions and related classes.'''


import hashlib
import hmac

from electrumx.lib.util import bytes_to_int, int_to_bytes, hex_to_bytes

_sha256 = hashlib.sha256
_sha512 = hashlib.sha512
_new_hash = hashlib.new
_new_hmac = hmac.new
HASHX_LEN = 11


def sha256(x):
'''Simple wrapper of hashlib sha256.'''
return _sha256(x).digest()


def ripemd160(x):
'''Simple wrapper of hashlib ripemd160.'''
h = _new_hash('ripemd160')
h.update(x)
return h.digest()


def double_sha256(x):
'''SHA-256 of SHA-256, as used extensively in bitcoin.'''
return sha256(sha256(x))


def hmac_sha512(key, msg):
'''Use SHA-512 to provide an HMAC.'''
return _new_hmac(key, msg, _sha512).digest()


def hash160(x):
'''RIPEMD-160 of SHA-256.
Used to make bitcoin addresses from pubkeys.'''
return ripemd160(sha256(x))


def hash_to_hex_str(x):
'''Convert a big-endian binary hash to displayed hex string.
Display form of a binary hash is reversed and converted to hex.
'''
return bytes(reversed(x)).hex()


def hex_str_to_hash(x):
'''Convert a displayed hex string to a binary hash.'''
return bytes(reversed(hex_to_bytes(x)))


class Base58Error(Exception):
'''Exception used for Base58 errors.'''


class Base58(object):
'''Class providing base 58 functionality.'''

chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
assert len(chars) == 58
cmap = {c: n for n, c in enumerate(chars)}

@staticmethod
def char_value(c):
val = Base58.cmap.get(c)
if val is None:
raise Base58Error('invalid base 58 character "{}"'.format(c))
return val

@staticmethod
def decode(txt):
"""Decodes txt into a big-endian bytearray."""
if not isinstance(txt, str):
raise TypeError('a string is required')

if not txt:
raise Base58Error('string cannot be empty')

value = 0
for c in txt:
value = value * 58 + Base58.char_value(c)

result = int_to_bytes(value)

# Prepend leading zero bytes if necessary
count = 0
for c in txt:
if c != '1':
break
count += 1
if count:
result = bytes(count) + result

return result

@staticmethod
def encode(be_bytes):
"""Converts a big-endian bytearray into a base58 string."""
value = bytes_to_int(be_bytes)

txt = ''
while value:
value, mod = divmod(value, 58)
txt += Base58.chars[mod]

for byte in be_bytes:
if byte != 0:
break
txt += '1'

return txt[::-1]

@staticmethod
def decode_check(txt, *, hash_fn=double_sha256):
'''Decodes a Base58Check-encoded string to a payload. The version
prefixes it.'''
be_bytes = Base58.decode(txt)
result, check = be_bytes[:-4], be_bytes[-4:]
if check != hash_fn(result)[:4]:
raise Base58Error('invalid base 58 checksum for {}'.format(txt))
return result

@staticmethod
def encode_check(payload, *, hash_fn=double_sha256):
"""Encodes a payload bytearray (which includes the version byte(s))
into a Base58Check string."""
be_bytes = payload + hash_fn(payload)[:4]
return Base58.encode(be_bytes)
Loading

0 comments on commit 89d1bcd

Please sign in to comment.