mirror of
https://github.com/planetmint/planetmint.git
synced 2025-11-24 14:35:45 +00:00
* adjusted hashlib imports and renamed to bigchaindb error Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added type hints to transactions module Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved upsert_validator txs to transactions, updated imports Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed unused imports Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved tx validate to lib Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved from_db to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed from db from transaction Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved election validation to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved election methods to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved get_validators and get_recipients to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed unnecessary election method Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved show_election_status to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved topology check to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved election_id_to_public_key to validator_utils Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved vote methods to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved process_block to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed unused code from Vote Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved has election concluded to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * adjusted has_election_concluded Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed unused imports, added copyright notices Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved rollback_eleciton to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved on_rollback behaviour to planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved some validator utils to tendermint utils, election approval now handled by planetmint Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * Use planetmint-transaction pypi package Signed-off-by: cybnon <stefan.weber93@googlemail.com> * fixed docs imports Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed validate call on test case Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * resolved linting errors Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed mock on test case Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * adjusted CHANGELOG Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed duplicate transactions test suite Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed pr comments Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * reordered imports to be standardized Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed unused imports and reordered them Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed linter error Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> Signed-off-by: cybnon <stefan.weber93@googlemail.com> Co-authored-by: cybnon <stefan.weber93@googlemail.com>
212 lines
6.2 KiB
Python
212 lines
6.2 KiB
Python
# Copyright © 2020 Interplanetary Database Association e.V.,
|
|
# Planetmint and IPDB software contributors.
|
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
|
|
|
import contextlib
|
|
import threading
|
|
import queue
|
|
import multiprocessing as mp
|
|
import json
|
|
import setproctitle
|
|
|
|
from packaging import version
|
|
from planetmint.version import __tm_supported_versions__
|
|
from planetmint.tendermint_utils import key_from_base64
|
|
from transactions.common.crypto import key_pair_from_ed25519_key
|
|
|
|
|
|
class ProcessGroup(object):
|
|
def __init__(self, concurrency=None, group=None, target=None, name=None, args=None, kwargs=None, daemon=None):
|
|
self.concurrency = concurrency or mp.cpu_count()
|
|
self.group = group
|
|
self.target = target
|
|
self.name = name
|
|
self.args = args or ()
|
|
self.kwargs = kwargs or {}
|
|
self.daemon = daemon
|
|
self.processes = []
|
|
|
|
def start(self):
|
|
for i in range(self.concurrency):
|
|
proc = mp.Process(
|
|
group=self.group,
|
|
target=self.target,
|
|
name=self.name,
|
|
args=self.args,
|
|
kwargs=self.kwargs,
|
|
daemon=self.daemon,
|
|
)
|
|
proc.start()
|
|
self.processes.append(proc)
|
|
|
|
|
|
class Process(mp.Process):
|
|
"""Wrapper around multiprocessing.Process that uses
|
|
setproctitle to set the name of the process when running
|
|
the target task.
|
|
"""
|
|
|
|
def run(self):
|
|
setproctitle.setproctitle(self.name)
|
|
super().run()
|
|
|
|
|
|
# Inspired by:
|
|
# - http://stackoverflow.com/a/24741694/597097
|
|
def pool(builder, size, timeout=None):
|
|
"""Create a pool that imposes a limit on the number of stored
|
|
instances.
|
|
|
|
Args:
|
|
builder: a function to build an instance.
|
|
size: the size of the pool.
|
|
timeout(Optional[float]): the seconds to wait before raising
|
|
a ``queue.Empty`` exception if no instances are available
|
|
within that time.
|
|
Raises:
|
|
If ``timeout`` is defined but the request is taking longer
|
|
than the specified time, the context manager will raise
|
|
a ``queue.Empty`` exception.
|
|
|
|
Returns:
|
|
A context manager that can be used with the ``with``
|
|
statement.
|
|
|
|
"""
|
|
|
|
lock = threading.Lock()
|
|
local_pool = queue.Queue()
|
|
current_size = 0
|
|
|
|
@contextlib.contextmanager
|
|
def pooled():
|
|
nonlocal current_size
|
|
instance = None
|
|
|
|
# If we still have free slots, then we have room to create new
|
|
# instances.
|
|
if current_size < size:
|
|
with lock:
|
|
# We need to check again if we have slots available, since
|
|
# the situation might be different after acquiring the lock
|
|
if current_size < size:
|
|
current_size += 1
|
|
instance = builder()
|
|
|
|
# Watchout: current_size can be equal to size if the previous part of
|
|
# the function has been executed, that's why we need to check if the
|
|
# instance is None.
|
|
if instance is None:
|
|
instance = local_pool.get(timeout=timeout)
|
|
|
|
yield instance
|
|
|
|
local_pool.put(instance)
|
|
|
|
return pooled
|
|
|
|
|
|
# TODO: Rename this function, it's handling fulfillments not conditions
|
|
def condition_details_has_owner(condition_details, owner):
|
|
"""Check if the public_key of owner is in the condition details
|
|
as an Ed25519Fulfillment.public_key
|
|
|
|
Args:
|
|
condition_details (dict): dict with condition details
|
|
owner (str): base58 public key of owner
|
|
|
|
Returns:
|
|
bool: True if the public key is found in the condition details, False otherwise
|
|
|
|
"""
|
|
if "subconditions" in condition_details:
|
|
result = condition_details_has_owner(condition_details["subconditions"], owner)
|
|
if result:
|
|
return True
|
|
|
|
elif isinstance(condition_details, list):
|
|
for subcondition in condition_details:
|
|
result = condition_details_has_owner(subcondition, owner)
|
|
if result:
|
|
return True
|
|
else:
|
|
if "public_key" in condition_details and owner == condition_details["public_key"]:
|
|
return True
|
|
return False
|
|
|
|
|
|
class Lazy:
|
|
"""Lazy objects are useful to create chains of methods to
|
|
execute later.
|
|
|
|
A lazy object records the methods that has been called, and
|
|
replay them when the :py:meth:`run` method is called. Note that
|
|
:py:meth:`run` needs an object `instance` to replay all the
|
|
methods that have been recorded.
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""Instantiate a new Lazy object."""
|
|
self.stack = []
|
|
|
|
def __getattr__(self, name):
|
|
self.stack.append(name)
|
|
return self
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
self.stack.append((args, kwargs))
|
|
return self
|
|
|
|
def __getitem__(self, key):
|
|
self.stack.append("__getitem__")
|
|
self.stack.append(([key], {}))
|
|
return self
|
|
|
|
def run(self, instance):
|
|
"""Run the recorded chain of methods on `instance`.
|
|
|
|
Args:
|
|
instance: an object.
|
|
"""
|
|
|
|
last = instance
|
|
|
|
for item in self.stack:
|
|
if isinstance(item, str):
|
|
last = getattr(last, item)
|
|
else:
|
|
last = last(*item[0], **item[1])
|
|
|
|
self.stack = []
|
|
return last
|
|
|
|
|
|
# Load Tendermint's public and private key from the file path
|
|
def load_node_key(path):
|
|
with open(path) as json_data:
|
|
priv_validator = json.load(json_data)
|
|
priv_key = priv_validator["priv_key"]["value"]
|
|
hex_private_key = key_from_base64(priv_key)
|
|
return key_pair_from_ed25519_key(hex_private_key)
|
|
|
|
|
|
def tendermint_version_is_compatible(running_tm_ver):
|
|
"""
|
|
Check Tendermint compatability with Planetmint server
|
|
|
|
:param running_tm_ver: Version number of the connected Tendermint instance
|
|
:type running_tm_ver: str
|
|
:return: True/False depending on the compatability with Planetmint server
|
|
:rtype: bool
|
|
"""
|
|
|
|
# Splitting because version can look like this e.g. 0.22.8-40d6dc2e
|
|
tm_ver = running_tm_ver.split("-")
|
|
if not tm_ver:
|
|
return False
|
|
for ver in __tm_supported_versions__:
|
|
if version.parse(ver) == version.parse(tm_ver[0]):
|
|
return True
|
|
return False
|