forked from sumcoinlabs/electrumx-sum
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
4,189 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Oops, something went wrong.