Exemple #1
0
def extract(username):
    now = datetime.datetime.now(tz=pytz.UTC)

    if getPublicKeyFromUsername(username):
        param = loadJson("%s.json" % username)
        threshold = param.get("threshold", 0.2)
        share = param.get("share", 1.0)

        forgery = loadJson("%s.forgery" % username, os.path.join(zen.DATA, username))
        data = OrderedDict(sorted([[a,w] for a,w in forgery.get("contributions", {}).items()], key=lambda e:e[-1], reverse=True))
        tbw = OrderedDict([a,w*share] for a,w in data.items() if w*share >= threshold)
        totalDistributed = sum(tbw.values())

        dumpJson(
            {
                "timestamp": "%s" % now,
                "delegate-share": round(forgery.get("blocks", 0.) * dposlib.rest.cfg.blockreward * (1.0 - share), 8),
                "undistributed": round(sum(w for w in data.values() if w < threshold), 8),
                "distributed": round(totalDistributed, 8),
                "fees": round(forgery.get("fees", 0.), 8),
                "weight": OrderedDict(sorted([[a,s/totalDistributed] for a,s in tbw.items()], key=lambda e:e[-1], reverse=True))
            },
            "%s.tbw" % now.strftime("%Y%m%d-%H%M"),
            folder=os.path.join(zen.ROOT, "app", ".tbw", username)
        )

        # reset forgery keeping unpaind voters
        forgery["contributions"] = OrderedDict([a, 0. if a in tbw else w] for a,w in data.items())
        forgery["blocks"] = 0
        forgery["fees"] = 0.
        dumpJson(forgery, "%s.forgery" % username, os.path.join(zen.DATA, username))
Exemple #2
0
def configure(**kwargs):
    if "username" in kwargs:
        username = kwargs.pop("username")
        if getPublicKeyFromUsername(username):
            if not os.path.exists(
                    os.path.join(zen.JSON, "%s-webhook.json" % username)):
                if not setDelegate(username,
                                   peer=kwargs.get("webhook_peer", None)):
                    return
                zen.logMsg("%s delegate webhook set" % username)
            else:
                # load update and save in a row
                zen.dumpJson(
                    dict(zen.loadJson("%s.json" % username), **kwargs),
                    "%s.json" % username)
                zen.logMsg("%s delegate set" % username)
        else:
            zen.logMsg("can not find delegate %s" % username)

    elif not len(kwargs):
        root = zen.loadJson("root.json")
        if "env" in root:
            delegates = zen.loadJson("delegates.json",
                                     os.path.dirname(root["env"]))
            for secret in delegates["secrets"]:
                setDelegate(dposlib.core.crypto.getKeys(secret)["publicKey"])
Exemple #3
0
def updateRegistryNonces(username):
    folder = os.path.join(zen.DATA, username)
    registries = [n for n in os.listdir(folder) if n.endswith(".registry")]
    if not len(registries):
        return False

    KEYS01, KEYS02 = getKeys(username)
    wallet = rest.GET.api.wallets(username).get("data", {})
    nonce = int(wallet["nonce"]) + 1

    if KEYS01 and len(wallet):
        for name in registries:
            full_registry = loadJson(name, folder=folder)
            registry = loadJson(name+".milestone", folder=folder)
            if len(registry):
                logMsg("updating transaction nonces in %s..." % (name+".milestone"))
                for tx in list(registry.values()):
                    old_id = tx["id"]
                    new_tx = dposlib.core.Transaction(tx)
                    new_tx.nonce = nonce
                    nonce += 1
                    new_tx.signWithKeys(KEYS01["publicKey"], KEYS01["privateKey"])
                    if KEYS02 is not None:
                        new_tx.signSignWithKey(KEYS02["privateKey"])
                    new_tx.identify()
                    registry.pop(old_id)
                    full_registry.pop(old_id)
                    registry[new_tx["id"]] = new_tx
                    full_registry[new_tx["id"]] = new_tx
            dumpJson(registry, name+".milestone", folder=folder)
            dumpJson(full_registry, name, folder=folder)

    return True
Exemple #4
0
def _enableTask(delay, func, **params):
    if func not in ["enableTask", "disableTask"]:
        config = zen.loadJson("root.json")
        params.update(interval=delay)
        config["tasks-enabled"] = dict(
            config.get("tasks-enabled", {}), **{
                func: dict([k.replace("_", "-"), v] for k, v in params.items())
            })
        zen.dumpJson(config, "root.json")
Exemple #5
0
def setDelegate(uname_or_puk, peer=None):
    peer = zen.WEBHOOK_PEER if peer is None else peer
    account = dposlib.rest.GET.api.wallets(uname_or_puk).get("data", {})
    attributes = account.get("attributes", {})

    if attributes.get("delegate", False):
        username = attributes["delegate"]["username"]
        config = zen.loadJson("%s.json" % username)
        config["publicKey"] = account["publicKey"]
        zen.logMsg("%s configuration:" % username)

        if "#1" not in config:
            config["#1"] = askPrivateKey("enter first secret: ",
                                         config["publicKey"])
            if not config.get("#1", False):
                zen.logMsg("\ndelegate identification failed")
                return False

        if "secondPublicKey" in attributes:
            config["#2"] = askPrivateKey("enter second secret: ",
                                         attributes["secondPublicKey"])
            if not config.get("#2", False):
                zen.logMsg("\ndelegate identification failed")
                return False

        overwrite = input("Overwrite previous webhoook?[Y/n] ") \
            if os.path.exists(
                os.path.join(zen.JSON, "%s-webhook.json" % username)
            ) else "y"

        if overwrite in "yY":
            if not waitForPeer(peer):
                zen.logMsg("%s peer unreachable" % peer)
                return False
            webhook = setWebhook(config["publicKey"])
            if "token" in webhook:
                webhook["peer"] = peer
                zen.logMsg("webhook subscription succeded")
                zen.dumpJson(webhook, "%s-webhook.json" % username)
            else:
                zen.logMsg("an error occured with webhook subscription:\n%s" %
                           webhook)

        zen.dumpJson(config, "%s.json" % username)

    else:
        zen.logMsg(
            "%s seems not to be a valid delegate username or public key" %
            uname_or_puk)
        return False

    return True
Exemple #6
0
def checkIfForging():
    config = zen.loadJson("root.json").get("tasks-enabled",
                                           {}).get("checkIfForging", {})
    active_delegates = zen.biom.dposlib.rest.cfg.activeDelegates
    notification_delay = config.get("notification-delay", 10 * 60)
    monitored_peer = config.get("monitored-peer", zen.API_PEER)
    usernames = [
        name.split("-")[0] for name in os.listdir(zen.JSON)
        if name.endswith("-webhook.json")
    ]

    for user in usernames:
        dlgt = _GET.api.delegates(user, peer=monitored_peer).get("data", {})
        last_block = dlgt.get("blocks", {}).get("last", {})
        last_computed_block = zen.loadJson("%s.last.block" % user,
                                           folder=zen.DATA)
        if dlgt and last_computed_block == {}:
            zen.dumpJson(last_block, "%s.last.block" % user, folder=zen.DATA)
            return False
        elif dlgt.get("rank", 52) <= active_delegates:
            blkchn = _GET.api.blockchain(peer=monitored_peer).get("data", {})
            height = blkchn.get("block", {}).get("height", 0)
            current_round = (height - 1) // active_delegates
            dlgt_round = (last_block["height"] - 1) // active_delegates

            diff = current_round - dlgt_round
            missed = last_computed_block.get("missed", 0)
            if diff > 1:
                now = time.time()
                last_computed_block["missed"] = missed + 1
                delay = now - last_computed_block.get("notification", 0)
                msg = ("%s just missed a block" % user) if missed < 1 else (
                    "%s is missing blocks (total %d)" % (user, missed + 1))
                if delay > notification_delay:
                    zen.misc.notify(msg)
                    last_computed_block["notification"] = now
            elif missed > 0:
                msg = "%s is forging again" % user
                zen.misc.notify(msg)
                last_computed_block.pop("notification", False)
                last_computed_block.pop("missed", False)
            else:
                msg = "%s is forging" % user

            last_computed_block.update(last_block)
            zen.dumpJson(last_computed_block,
                         "%s.last.block" % user,
                         folder=zen.DATA)
            zen.logMsg("round check [delegate:%d | blockchain:%d] - %s" %
                       (dlgt_round, current_round, msg))
    return True
Exemple #7
0
def pushBackKeys():
    module = sys.modules[__name__]
    delegates = []
    for key, value in [(k, v) for k, v in module.__dict__.items()
                       if k[-2:] in "#1#2"]:
        username, num = key.replace("_", "").split("#")
        num = "#" + num
        config = zen.loadJson("%s.json" % username)
        config[num] = value
        zen.dumpJson(config, "%s.json" % username)
        delegates.append(username)

    for username in set(delegates):
        zen.logMsg("%s secrets pushed back" % username)
Exemple #8
0
def regenerateUnapplied(username, filename):
    registry = zen.loadJson("%s.registry" % filename,
                            os.path.join(zen.DATA, username))
    tbw = zen.loadJson("%s.tbw" % filename,
                       os.path.join(zen.TBW, username, "history"))

    for tx in registry.values():
        if not transactionApplied(tx["id"]):
            zen.logMsg('tx %(id)s [%(amount)s --> %(recipientId)s] unapplied' %
                       tx)
        else:
            tbw["weight"].pop(tx["recipientId"], False)

    zen.dumpJson(tbw, '%s-unapplied.tbw' % filename,
                 os.path.join(zen.TBW, username))
Exemple #9
0
def adjust(username, value):
    if getPublicKeyFromUsername(username):
        folder = os.path.join(zen.DATA, username)
        forgery = loadJson("%s.forgery" % username, folder=folder)
        total = sum(forgery["contributions"].values())
        dumpJson(
            {
                "fees": forgery.get("fees", 0.),
                "blocks": forgery.get("blocks", 0),
                "contributions": OrderedDict(sorted([[a, v/total*value] for a,v in forgery["contributions"].items()], key=lambda e:e[-1], reverse=True))
            },
            "%s.forgery" % username,
            folder=folder
        )
    else:
        logMsg("%s username does not exist" % username)
Exemple #10
0
def pullKeys():
    module = sys.modules[__name__]
    for username in [
            n.replace("-webhook.json", "") for n in next(os.walk(zen.JSON))[-1]
            if n.endswith("-webhook.json")
    ]:
        config = zen.loadJson("%s.json" % username)
        hide = False
        if "#1" in config:
            setattr(module, "_%s_#1" % username, config.pop("#1"))
            hide = True
        if "#2" in config:
            setattr(module, "_%s_#2" % username, config.pop("#2"))
            hide = True
        if hide:
            zen.logMsg("%s secrets pulled" % username)
            zen.dumpJson(config, "%s.json" % username)
Exemple #11
0
def deploy(host="127.0.0.1", port=5000):
    root = zen.loadJson("root.json")
    root["port"] = port
    root["host"] = host
    zen.dumpJson(root, "root.json")
    normpath = os.path.normpath
    executable = normpath(sys.executable)
    gunicorn_conf = os.path.normpath(
        os.path.abspath(os.path.expanduser("~/ark-zen/gunicorn.conf.py")))

    with io.open("./zen.service", "w") as unit:
        unit.write(
            u"""[Unit]
Description=Zen TBW server
After=network.target

[Service]
User=%(usr)s
WorkingDirectory=%(wkd)s
Environment=PYTHONPATH=%(path)s:${HOME}/dpos
ExecStart=%(bin)s/gunicorn zen.app:app \
--bind=%(host)s:%(port)d --workers=5 --timeout 10 --access-logfile -
Restart=always

[Install]
WantedBy=multi-user.target
""" % {
                "host": host,
                "port": port,
                "usr": os.environ.get("USER", "unknown"),
                "wkd": normpath(sys.prefix),
                "path": normpath(os.path.dirname(zen.__path__[0])),
                "bin": os.path.dirname(executable),
            })

    if os.system("%s -m pip show gunicorn" % executable) != "0":
        os.system("%s -m pip install gunicorn" % executable)
    os.system("chmod +x ./zen.service")
    os.system("sudo cp %s %s" % (gunicorn_conf, normpath(sys.prefix)))
    os.system("sudo mv --force ./zen.service /etc/systemd/system")
    os.system("sudo systemctl daemon-reload")
    if not os.system("sudo systemctl restart zen"):
        os.system("sudo systemctl start zen")
Exemple #12
0
def download_backup():
    if flask.request.method == "POST":
        challenge = zen.loadJson("challenge.json")
        value = flask.request.form.get("value")
        if time.time() > challenge.get("expiration", 0):
            return "", 408
        elif challenge.get("value", "") != value:
            return "", 403
        else:
            return flask.send_file(os.path.abspath(
                os.path.join(zen.__path__[0], "data-bkp.tar.bz2")),
                                   as_attachment=True)

    challenge = "%s" % int(
        hashlib.sha256(binascii.hexlify(os.urandom(32))).hexdigest()[:5], 16)
    zen.dumpJson({
        "value": challenge,
        "expiration": time.time() + 60
    }, "challenge.json")
    zen.misc.notify("Your challenge code is:\n%s" % challenge)
    return flask.render_template("backup.html")
Exemple #13
0
def setDelegate(pkey, webhook_peer, public=False):
    printNewLine()
    # for each publicKey, get account data (merge delegate and wallet info)
    req = rest.GET.api.delegates(pkey).get("data", {})
    account = rest.GET.api.wallets(pkey).get("data", {})
    account.update(req)

    if account != {}:
        username = account["username"]
        logMsg("setting up %s delegate..." % username)
        # load forger configuration and update with minimum data
        config = loadJson("%s.json" % username)
        config.update(**{"publicKey":pkey, "#2":askSecret(account, cmp_key="secondPublicKey")})
        dumpJson(config, "%s.json" % username)
        # create a webhook if no one is set
        webhook = loadJson("%s-webhook.json" % username)
        if not webhook.get("token", False):
            data = rest.POST.api.webhooks(
                peer=webhook_peer,
                event="block.forged",
                target="http://%s:5000/block/forged" % (zen.PUBLIC_IP if public else "127.0.0.1"),
                conditions=[{"key": "generatorPublicKey", "condition": "eq", "value": pkey}]
            )
            webhook = data.get("data", False)
            if webhook:
                webhook["peer"] = webhook_peer
                dumpJson(webhook, "%s-webhook.json" % username)
                logMsg("%s webhook set" % username)
            else:
                logMsg("error occur on webhook creation:\n%s" % data)
        else:
            logMsg("webhook already set for delegate %s" % username)
        logMsg("%s delegate set" % username)
        return account
    else:
        logMsg("%s: %s" % (req.get("error", "API Error"), req.get("message", "...")))
Exemple #14
0
def start():
    global DAEMON, IS_SYNCING, STATUS, SEED_STATUS
    sleep_time = zen.rest.cfg.blocktime * zen.rest.cfg.activeDelegates

    data = zen.loadJson("bg-marker.json")
    data["stop"] = False
    zen.dumpJson(data, "bg-marker.json")

    DAEMON = threading.Event()
    # check health status every minutes
    daemon_1 = setInterval(60)(checkNode)()
    # generate svg charts every round
    daemon_2 = setInterval(sleep_time)(generateCharts)()
    # check all registries
    daemon_3 = setInterval(sleep_time)(checkRegistries)()
    # check updates
    daemon_4 = setInterval(5 * sleep_time)(checkVersion)()
    # check forge
    daemon_5 = setInterval(30)(checkIfForging)()
    zen.logMsg("Background tasks started !")
    zen.misc.notify("Background tasks started !")

    try:
        while not DAEMON.is_set():
            time.sleep(sleep_time)
            zen.logMsg("sleep time finished :\n%s" %
                       zen.json.dumps(CHECK_RESULT))
    except KeyboardInterrupt:
        zen.logMsg("Background tasks interrupted !")

    daemon_1.set()
    daemon_2.set()
    daemon_3.set()
    daemon_4.set()
    daemon_5.set()
    zen.misc.notify("Background tasks stoped !")
Exemple #15
0
def checkApplied(username):
    folder = os.path.join(zen.DATA, username)
    sqlite = initDb(username)
    cursor = sqlite.cursor()

    for name in [n for n in os.listdir(folder) if n.endswith(".registry")]:
        full_registry = loadJson(name, folder=folder)
        # try to lad a milestone first, if no one exists
        registry = loadJson(name+".milestone", folder=folder)
        # if void dict returned by loadJson, then load registry file
        if not len(registry):
            registry = dict(full_registry) #loadJson(name, folder=folder)
            logMsg("starting transaction check from %s..." % name)
        else:
            logMsg("resuming transaction check from %s..." % (name+".milestone"))

        start = time.time()
        transactions = list(registry.values())
        for tx in transactions:
            if zen.misc.transactionApplied(tx["id"]):
                logMsg("transaction %(id)s <type %(type)s> applied" % registry.pop(tx["id"]))
                if "payments" in tx.get("asset", {}):
                    for record in tx["asset"]["payments"]:
                        cursor.execute(
                            "INSERT OR REPLACE INTO transactions(filename, timestamp, amount, address, id) VALUES(?,?,?,?,?);",
                            (os.path.splitext(name)[0], tx["timestamp"], int(record["amount"])/100000000., record["recipientId"], tx["id"])
                        )
            # set a milestone every 5 seconds
            if (time.time() - start) > 5.:
                sqlite.commit()
                dumpJson(registry, name+".milestone", folder=folder)
                logMsg("milestone set (%d transaction left to check)" % len(registry))
                start = time.time()
        dumpJson(registry, name+".milestone", folder=folder)

        if len(registry) == 0:
            dumpJson(full_registry, name, folder=os.path.join(folder, "backup"))
            try:
                os.remove(os.path.join(folder, name))
                os.remove(os.path.join(folder, name+".milestone"))
            except:
                pass
            checked_tx = full_registry.values()
            zen.misc.notify("Payroll successfully broadcasted !\n%.8f %s sent trough %d transactions" % (
                sum([sum([int(rec["amount"]) for rec in tx["asset"].get("payments", [])]) for tx in checked_tx])/100000000.,
                dposlib.rest.cfg.symbol,
                len(checked_tx)
            ))
        else:
            zen.misc.notify("Transactions are still to be checked (%d)..." % len(registry))

        sqlite.commit()
Exemple #16
0
def computeDelegateBlock(username, generatorPublicKey, block):
    # get reward and fees from block data
    rewards = float(block["reward"])/100000000.
    fees = float(block["totalFee"])/100000000.
    logMsg("%s forged %s : %.8f|%.8f" % (username, block["id"], rewards, fees))
    blocks = 1
    # Because sometime network is not in good health, the spread function
    # can exit with exception. So compare the ids of last forged blocks
    # to compute rewards and fees...
    filename = "%s.last.block" % username
    folder = os.path.join(zen.DATA, username)
    last_block = loadJson(filename, folder=folder)
    # if there is a <username>.last.block
    if last_block.get("id", False):
        logMsg("last known forged: %s" % last_block["id"])
        # get last forged blocks from blockchain
        # TODO : get all blocks till the last forged (not the 100 last ones)
        req = rest.GET.api.delegates(generatorPublicKey, "blocks")
        last_blocks = req.get("data", [])
        # raise Exceptions if issues with API call
        if not len(last_blocks):
            raise Exception("No new block found in peer response")
        elif req.get("error", False) != False:
            raise Exception("Api error : %r" % req.get("error", "?"))
        # compute fees, blocs and rewards from the last saved block
        for blk in last_blocks:
            _id = blk["id"]
            # stop the loop when last forged block is reach in the last blocks list
            if _id == last_block["id"]:
                break
            # if bc is not synch and response is too bad, also check timestamp
            elif _id != block["id"] and blk["timestamp"]["epoch"] > last_block["timestamp"]:
                logMsg("    getting rewards and fees from block %s..." % _id)
                rewards += float(blk["forged"]["reward"])/100000000.
                fees += float(blk["forged"]["fee"])/100000000.
                blocks += 1
            else:
                logMsg("    ignoring block %s (previously forged)" % _id)
    # else initiate <username>.last.block
    else:
        dumpJson(block, filename, folder=folder)
        raise Exception("First iteration for %s" % username)
    # find forger information using username
    forger = loadJson("%s.json" % username)
    forgery = loadJson("%s.forgery" % username, folder=folder)
    # compute the reward distribution excluding delegate
    address = dposlib.core.crypto.getAddress(generatorPublicKey)
    excludes = forger.get("excludes", [address])
    if address not in excludes:
        excludes.append(address)
    contributions = distributeRewards(
        rewards,
        username,
        minvote=forger.get("minimum_vote", 0),
        excludes=excludes
    )
    # dump true block weight data
    _ctrb = forgery.get("contributions", {})
    dumpJson(
        {
            "fees": forgery.get("fees", 0.) + fees,
            "blocks": forgery.get("blocks", 0) + blocks,
            "contributions": OrderedDict(sorted([[a, _ctrb.get(a, 0.)+contributions[a]] for a in contributions], key=lambda e:e[-1], reverse=True))
        },
        "%s.forgery" % username,
        folder=folder
    )
    # dump current forged block as <username>.last.block
    dumpJson(block, filename, folder=folder)
    # notify vote movements
    msg = "\n".join(
        ["%s removed from %s list [%.8f Arks]" % (zen.misc.shorten(wallet), username, _ctrb[wallet]) for wallet in [w for w in _ctrb if w not in contributions]] + \
        ["%s added to %s list" % (zen.misc.shorten(wallet), username) for wallet in [w for w in contributions if w not in _ctrb]]
    )
    logMsg("checking vote changes..." + (" nothing hapened !" if msg == "" else ("\n%s"%msg)))
    if msg != "":
        zen.misc.notify(msg)
Exemple #17
0
def init(**kwargs):
    webhook_peer = kwargs.get("webhook_peer", zen.WEBHOOK_PEER)
    root = loadJson("root.json")

    # if no options given, initialize forgers set on the node
    if not len(kwargs):
        # find delegates secrets and generate publicKeys
        env_folder = os.path.dirname(root["env"])
        if os.path.exists(os.path.join(env_folder, "delegates.json")):
            # ark core >= v2.1.x
            delegates = loadJson("delegates.json", env_folder)
        else:
            # ark core <= v2.0.x
            delegates = loadJson("delegates.json", os.path.join(env_folder, "config"))
        pkeys = [dposlib.core.crypto.getKeys(secret)["publicKey"] for secret in delegates["secrets"]]

        for pkey in set(pkeys):
            setDelegate(pkey, webhook_peer, webhook_peer != zen.WEBHOOK_PEER)

    elif "usernames" in kwargs:
        pkeys = []
        for username in kwargs.pop("usernames", []):
            req = rest.GET.api.delegates(username).get("data", {})
            if len(req):
                pkeys.append(req["publicKey"])

        for pkey in pkeys:
            account = setDelegate(pkey, webhook_peer, webhook_peer != zen.WEBHOOK_PEER)
            if account:
                config = loadJson("%s.json" % account["username"])
                config["#1"] = askSecret(account, cmp_key="publicKey")
                config.update(**kwargs)
                dumpJson(config, "%s.json" % account["username"])

    elif "username" in kwargs:
        username = kwargs.pop("username")
        if getPublicKeyFromUsername(username):
            config = loadJson("%s.json" % username)
            config.update(**kwargs)
            if not(config.get("fee_level", True)):
                config.pop("fee_level", None)
                logMsg("Dynamic fees disabled")
            dumpJson(config, "%s.json" % username)
            logMsg("%s delegate set" % username)
        else:
            logMsg("can not find delegate %s" % username)

    else:
        tbw = loadJson("tbw.json")
        for key in [k for k in ["target_delegate", "fee_coverage"] if k in kwargs]:
            value = kwargs.pop(key)
            if value:
                if key in tbw:
                    tbw.pop(key)
                    logMsg("%s disabled" % key)
                else:
                    tbw[key] = value
                    logMsg("%s enabled" % key)

        max_per_sender = int(kwargs.pop("max_per_sender", False))
        if max_per_sender != False:
            env = zen.loadEnv(root["env"])
            env["CORE_TRANSACTION_POOL_MAX_PER_SENDER"] = max_per_sender
            zen.dumpEnv(env, root["env"])
            zen.logMsg("env parameter CORE_TRANSACTION_POOL_MAX_PER_SENDER set to %d \n    ark-core-relay have to be restarted" % (max_per_sender))

        tbw.update(**kwargs)
        dumpJson(tbw, "tbw.json")
Exemple #18
0
def _disableTask(func):
    config = zen.loadJson("root.json")
    tasks = config.get("tasks-enabled", {})
    tasks.pop(func, None)
    config["tasks-enabled"] = tasks
    zen.dumpJson(config, "root.json")
Exemple #19
0
def dumpRegistry(username, chunk_size=50):
    folder = os.path.join(zen.ROOT, "app", ".tbw", username)
    tbw_files = [n for n in os.listdir(folder) if n.endswith(".tbw")]
    if not len(tbw_files):
        return False

    KEYS01, KEYS02 = getKeys(username)
    wallet = rest.GET.api.wallets(username).get("data", {})

    # for testing purpose
    # wallet = {
    # "address":"ARfDVWZ7Zwkox3ZXtMQQY1HYSANMB88vWE",
    # "publicKey":"030da05984d579395ce276c0dd6ca0a60140a3c3d964423a04e7abe110d60a15e9",
    # "nonce":"16973",
    # "balance":"160032168390",
    # "attributes":{
    #   "delegate":{
    #       "username":"******",
    #       "voteBalance":"182267782242191",
    #       "forgedFees":"447838954643",
    #       "forgedRewards":"44064800000000",
    #       "producedBlocks":221746,
    #       "rank":8,
    #       "lastBlock":{
    #           "version":0,"timestamp":93163312,
    #           "height":11498689,
    #           "previousBlockHex":"23ccc346f07fe6a22e2cb8420faf7ed53675e14b85ded3d55d5f3e118d987043",
    #           "previousBlock":"23ccc346f07fe6a22e2cb8420faf7ed53675e14b85ded3d55d5f3e118d987043",
    #           "numberOfTransactions":0,
    #           "totalAmount":"0",
    #           "totalFee":"0",
    #           "reward":"200000000",
    #           "payloadLength":0,
    #           "payloadHash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    #           "generatorPublicKey":"030da05984d579395ce276c0dd6ca0a60140a3c3d964423a04e7abe110d60a15e9",
    #           "blockSignature":"304402207026213f4376fa0270f257600b6825e559e1a43e1402182e1d6a9e2388573b1402202d631c2cc54ed8e9aeff0014d0d8efb31b706be1b38774be13a279ef239647da",
    #           "idHex":"e3dbd0b2647647bc5cb853f78d82fc9949dd2dc669469f5973622ce04a27fc0c",
    #           "id":"e3dbd0b2647647bc5cb853f78d82fc9949dd2dc669469f5973622ce04a27fc0c"
    #       },
    #       "round":225466
    #   },
    #   "vote":"02b54f00d9de5a3ace28913fe78a15afcfe242926e94d9b517d06d2705b261f992"
    # },
    # "isDelegate":True,
    # "isResigned":False,
    # "vote":"02b54f00d9de5a3ace28913fe78a15afcfe242926e94d9b517d06d2705b261f992",
    # "username":"******"
    # }

    if KEYS01 and len(wallet):
        config = loadJson("%s.json" % username)
        fee_level = config.get("fee_level", False)
        if fee_level:
            dposlib.core.Transaction.useDynamicFee(fee_level)
        else:
            dposlib.core.Transaction.useStaticFee()

        for name in tbw_files:
            data = loadJson(name, folder)
            amount = data["distributed"]

            totalFees = 0
            registry = OrderedDict()
            timestamp = slots.getTime()

            weights = sorted(data["weight"].items(), key=lambda e:e[-1], reverse=True)
            nonce = int(wallet["nonce"]) + 1

            while len(weights) % chunk_size <= 3:
                chunk_size -= 1

            for chunk in [weights[i:i+chunk_size] for i in range(0, len(weights), chunk_size)]:
                transaction = dposlib.core.multiPayment(
                    *[[round(amount*wght, 8), addr] for addr, wght in chunk],
                    vendorField=config.get("vendorField", "%s reward" % username)
                )
                if "vendorFieldHex" in config:
                    transaction.vendorFieldHex = config["vendorFieldHex"]
                dict.__setitem__(transaction, "senderPublicKey", wallet["publicKey"])
                transaction.nonce = nonce
                transaction.senderId = wallet["address"]
                transaction.timestamp = timestamp
                transaction.setFee()
                transaction.signWithKeys(KEYS01["publicKey"], KEYS01["privateKey"])
                if KEYS02 is not None:
                    transaction.signSignWithKey(KEYS02["privateKey"])
                transaction.identify()
                registry[transaction["id"]] = transaction
                totalFees += transaction["fee"]
                nonce += 1

            totalFees /= 100000000.0
            if config.get("wallet", False):
                transaction0 = dposlib.core.transfer(
                    round(data["delegate-share"] + data["fees"] - totalFees, 8),
                    config["wallet"], "%s share" % username,
                )
                dict.__setitem__(transaction0, "senderPublicKey", wallet["publicKey"])
                transaction0.nonce = nonce
                transaction0.senderId = wallet["address"]
                transaction0.timestamp = timestamp
                transaction0.setFee()
                transaction0.feeIncluded()
                transaction0.signWithKeys(KEYS01["publicKey"], KEYS01["privateKey"])
                if KEYS02 is not None:
                    transaction0.signSignWithKey(KEYS02["privateKey"])
                transaction0.identify()
                registry[transaction0["id"]] = transaction0

            dumpJson(registry, "%s.registry" % os.path.splitext(name)[0], os.path.join(zen.DATA, username))
            data["covered fees"] = totalFees
            dumpJson(data, name, os.path.join(folder, "history"))
            os.remove(os.path.join(folder, name))

    return True
Exemple #20
0
def checkIfForging():
    try:
        usernames = [
            name.split("-")[0] for name in os.listdir(zen.JSON)
            if name.endswith("-webhook.json")
        ]
        delegate_number = zen.dposlib.rest.cfg.activeDelegates
        notification_delay = 10 * 60  # 10 minutes in seconds

        for username in usernames:
            data = zen.dposlib.rest.GET.api.delegates(username) \
                .get("data", {}).get("blocks", {}).get("last", {})
            height = zen.dposlib.rest.GET.api.blockchain() \
                .get("data", {}).get("block", {}).get("height", 0)
            last_block = zen.loadJson("%s.last.block" % username,
                                      folder=zen.DATA)
            last_round = (data["height"] - 1) // delegate_number
            current_round = (height - 1) // delegate_number

            # if last forged block not found
            if last_block == {}:
                zen.dumpJson(data, "%s.last.block" % username, folder=zen.DATA)
            else:
                # get current height
                # custom parameters
                missed = last_block.get("missed", 0)
                last_notification = last_block.get("notification", 0)
                # blockchain parameters
                diff = current_round - last_round
                now = time.time()
                delay = now - last_notification

                if diff > 1:
                    rank = zen.dposlib.rest.GET.api.delegates(username) \
                           .get("data", {}).get("rank", -1)
                    if not rank:
                        zen.logMsg("delegate %s not found" % username)
                    send_notification = (rank <= delegate_number) and \
                                        (delay >= notification_delay)
                    # do the possible checks
                    if rank > delegate_number:
                        msg = "%s is not in forging position" % username
                        if delay >= notification_delay:
                            zen.misc.notify(msg)
                            last_block["notification"] = now
                    else:
                        msg = ("%s just missed a block" % username) if diff == 2 else \
                              ("%s is missing blocks (total %d)" % (username, missed + 1))
                        if send_notification:
                            zen.misc.notify(msg)
                            last_block["notification"] = now
                        last_block["missed"] = missed + 1
                elif missed > 0 or last_notification > 0:
                    msg = "%s is forging again" % username
                    zen.misc.notify(msg)
                    last_block.pop("missed", False)
                    last_block.pop("notification", False)
                else:
                    msg = "%s is forging" % username

                # dump last forged block info
                last_block.update(data)
                zen.dumpJson(last_block,
                             "%s.last.block" % username,
                             folder=zen.DATA)

            zen.logMsg("check if forging: %d | %d - %s" %
                       (last_round, current_round, msg))

    except Exception as e:
        zen.logMsg("chart generation error:\n%r\n%s" %
                   (e, traceback.format_exc()))
Exemple #21
0
def stop():
    data = zen.loadJson("bg-marker.json")
    data["stop"] = True
    zen.dumpJson(data, "bg-marker.json")
Exemple #22
0
def setup(clear=False, extern=False):
    # load root.json file. If not exists, root is empty dict
    root = zen.loadJson("root.json")
    # delete all keys from root dict if asked
    if clear:
        root.clear()
    #
    if extern:
        root["config-folder"] = None
    elif "appnames" not in root:
        try:
            root["appnames"] = identify_app()
        except Exception:
            pass
    # first configuration if no config-folder, it is set to "" because None is
    # used when zen is not running on a blockchain node
    if root.get("config-folder", "") == "":
        # if ark config directory found
        if os.path.isdir(os.path.expanduser("~/.config/ark-core")):
            root["config-folder"] = os.path.abspath(
                os.path.expanduser("~/.config/ark-core"))
        else:
            ans = "None"
            try:
                while ans not in "nNyY":
                    ans = input("Is zen installed on a running node ?[Y/n] ")
            except KeyboardInterrupt:
                zen.logMsg("\nconfiguration aborted...")
                return

            if ans in "yY":
                while not os.path.exists(root.get("config-folder", "")):
                    try:
                        root["config-folder"] = os.path.abspath(
                            input("Enter config folder: "))
                    except KeyboardInterrupt:
                        zen.logMsg("\nconfiguration aborted...")
                        return
            else:
                root["config-folder"] = None
    # if zen is running on a blockchain node
    if root["config-folder"] is not None:
        # get folder containing node configuration
        network = zen.chooseItem("select network:",
                                 *list(os.walk(root["config-folder"]))[0][1])
        if not network:
            zen.logMsg("configuration aborted...")
            return
        root["name"] = network
        root["env"] = os.path.join(root["config-folder"], network, ".env")
        root["blockchain"] = zen.loadJson("config.json",
                                          folder=os.path.join(
                                              root["config-folder"],
                                              network)).get("token", None)
        # load .env file and enable webhooks if disabled
        if not os.path.exists(root["env"]):
            zen.logMsg("no env file available...")
            return
        zen.ENV = loadEnv(root["env"])
        if not zen.ENV.get("CORE_WEBHOOKS_ENABLED", "") == "true":
            zen.ENV["CORE_WEBHOOKS_ENABLED"] = "true"
            zen.ENV["CORE_WEBHOOKS_HOST"] = "0.0.0.0"
            zen.ENV["CORE_WEBHOOKS_PORT"] = "4004"
            dumpEnv(zen.ENV, root["env"])
            if input(
                    "webhooks are now enabled, restart relay ?[Y/n] ") in "yY":
                start_pm2_app(identify_app().get("relay"))
    # if zen is not running on a blockchain node
    else:
        # get webhook subscription peer address
        try:
            root["webhook"] = input("Peer address for webhook submition: ")
            while dposlib.rest.GET.api.webhooks(
                    peer=root.get("webhook", "http://127.0.0.1:4004"),
                    timeout=2).get("status", False) != 200:
                root["webhook"] = input("Peer address for webhook submition: ")
        except KeyboardInterrupt:
            zen.logMsg("\nconfiguration aborted...")
            return
        root["webhook"] = root["webhook"]
        # get monitored node api address
        try:
            root["api"] = input("Peer address for API requests: ")
            while "data" not in dposlib.rest.GET.api.blockchain(peer=root.get(
                    "api", "http://127.0.0.1:4003"),
                                                                timeout=2):
                root["api"] = input("Peer address for API requests: ")
        except KeyboardInterrupt:
            zen.logMsg("\nconfiguration aborted...")
            return
        root["api"] = root["api"]

    # final check
    if root.get("blockchain", "") not in dir(dposlib.net):
        root["blockchain"] = zen.chooseItem(
            "Select blockchain running on node:", *[
                name for name in dir(dposlib.net)
                if not name.startswith("_") and getattr(
                    dposlib.net, name, {}).get("familly", None) == "ark"
            ])

    if not root["blockchain"]:
        zen.logMsg("blockchain can not be determined...")
        return
    else:
        zen.logMsg("configuration done")
        zen.dumpJson(root, "root.json")