Firmware (LuxOS)
Tools
luxos (python)
Introduction

Welcome to Luxos tooling

The luxos (opens in a new tab) python package provides:

  1. A cli script luxos, allowing to run a single command on miners
  2. A script luxos-run to run scriptlets on miners in parallel (using asyncio)
  3. A consistent API to access miners functionality through the the luxos python package

For simple to follow example on how to use the API see here

Install

Detailed instruction on how to install it are provided 👉 here, to install the latest released code:

# to install it
$> pip install luxos
 
# to upgrade it
$> pip install --upgrade luxos
 
# to verify the current version
$> python -c "import luxos; print(luxos.__version__, luxos.__hash__)"
0.0.7 27e53c7b37ac1bbb88112f3c931b9cd8f1a74a3a

luxos command line tool

The luxos (opens in a new tab) python package comes with a command line script called luxos: it can issue a command (with parameters) to a list of miners' ips in a csv file.

This will launch the version command on a miner, returning the json output:

luxos --range 127.0.0.1 --quiet --json --cmd version

The --range flag can take:

  • a single ip address, eg: --range 127.0.0.1
  • a range like: --range 127.0.0.1-127.0.0.5
  • or addresses from a file: --range @miners.csv.

Other examples:

# set/unset ATM
luxos --range 127.0.0.1 --quiet --json --cmd atmset --params "enabled=true"
 
# add a new profile
luxos --range 127.0.0.1 --quiet --json --cmd profilenew --params "myprofile,700,14.8"

NOTE

  1. --ipfile is an alternative way to load miners from a csv file, it's the same as --range flag: it can take addresses like 127.0.0.1, ranges as 127.0.0.1-127.0.0.5 or filenames as @miners.csv.
  2. you can use the --json to save the results in json format (to stdout).

luxos-run command line tool

The luxos-run is an alternative to luxos command line script, allowing to run as scriptlet (a small python script) targeting miners: a scriptlet usually can contain some logic and or longer commands sequences.

hello-world.py scriplet:

from luxos import asyncops
 
async def main(host: str, port: int):
    # async sending to the miner the version command
    res = await asyncops.rexec(host, port, "version")
 
    # validate will check the message is correct and return the result
    version = asyncops.validate(res, "VERSION", 1, 1)
    return {"address": f"{host}:{port}", "miner": version["LUXminer"]}

Running the luxos-run will execute the scriptlet aggregating the results in a dictionary with key set to the miner address:

luxos-run --range @miners.csv --quiet --json hello-world.py
{
  "127.0.0.1:4028": {
    "address": "127.0.0.1:4028",
    "version": "2021.1.12.202305-nnnn"
  }
}

The python api

luxos (opens in a new tab) python package comes with an API to support miners operations. The main fuctions are stored in the module for convenience and they are:

the rexec function

The rexec (opens in a new tab) function allows to send a command to a miner and return the response:

 
    from luxos import utils
    res = utils.asyncio.run(utils.rexec("127.0.0.1", 4028, "version"))
    # this is the validate helper
    print(utils.validate(res, "VERSION", 1, 1))

The full signature for rexec takes care of formatting the parameters, the full signature is:

rexec(
    host="127.0.0.1", port=4028,
    cmd="version", parameters="",
    timeout=2., retry=1, retry_delay=3.)

parameters can be a string, a list of any type (it will be converted into a str) or a dictionary (same conversion to string will apply).

timeout is the timeout for a call retry is the number of try before giving up retry_delay controls the delay between retry.

NOTE rexec is an async function, but there's a sync version under luxos.syncops.rexec.

launch

The luxos.utils.lauch allows to rexec commands to a list of miners stored in a csv file. This all-in-one function, allows batched operations on a set of miners, taking care of all details.

import asyncio
from luxos import utils
 
# load miners addresses from miners.csv
addresses = utils.load_ips_from_csv("miners.csv")
 
 
# define a task with (host, port) signature, acting on a miner
async def task(host: str, port: int):
    return await utils.rexec(host, port, "version")
 
# execute task across all miners, batch will limit execution rate to 4
asyncio.run(utils.launch(addresses, task, batch=4))
 
# a one liner
asyncio.run(utils.launch(addresses, lambda h, p: utils.rexec(h, p, "version"), batch=None))