From ac324552a9a3b923c1a0a562d6f3f8397e4a41ac Mon Sep 17 00:00:00 2001 From: Miguel Montes <miguel.montes@gmail.com> Date: Thu, 25 Oct 2018 18:21:34 -0300 Subject: [PATCH] =?UTF-8?q?Versi=C3=B3n=20inicial=20de=20sealer=5Fstatus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sealer_status/README.md | 77 ++++++++++++++++++++++++++++++++++ sealer_status/sealer_status.js | 45 ++++++++++++++++++++ sealer_status/sealer_status.py | 52 +++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 sealer_status/README.md create mode 100644 sealer_status/sealer_status.js create mode 100755 sealer_status/sealer_status.py diff --git a/sealer_status/README.md b/sealer_status/README.md new file mode 100644 index 0000000..552f1bc --- /dev/null +++ b/sealer_status/README.md @@ -0,0 +1,77 @@ +# Sealer status + +Se trata de dos _scripts_ que reportan la última aparición de cada uno de los selladores, buscando en los últimos bloques de la cadena hasta un cierto máximo (por default 720 bloques, es decir una hora). + +## `sealer_status.js` + +Escrito en JavaScript, puede ejecutarse desde la consola JavaScript de `geth`. + +Por ejemplo, en una instalación tÃpica de BFA: + +``` +bfa@bootnode:~$ geth attach ipc:/home/bfa/bfa/network/node/geth.ipc --exec 'loadScript("sealer_status.js")' +9b3ac6719b02ec7bb48: 466728 +998c2651db6f76ca568: 466727 +c0310a7b3b25f49b11b: 466726 +609043ebde4a06bd28a: 466725 +46991ada2a2544468eb: 466724 +91c055c6478bd0ad6d1: 466723 +39170a1ce03729d141d: 466722 +2feb6a8876bd9e2116b: 466721 +19fe7b9b3a1bebde77c: 466720 +342e1d075d820ed3f9d: -1 +true +bfa@bootnode:~$ +``` + +Para cada sellador reporta el último bloque que selló. Si un sellador no apareció en los últimos 720 bloques, reporta -1. + +## `sealer_status.py` + +Este es un _script_ escrito en Python, que requiere Python 3 y la biblioteca web3 (que puede instalarse con `pip`). + +Para funcionar requiere conocer el directorio donde está el _socket_ `geth.ipc` (asume que es `${BFANETWORKDIR}/node/geth.ipc` o, en su defecto `~/bfa/network/node/geth.ipc`), y el puerto RPC (asume que es el 8545). Ambos valores pueden especificarse en la lÃnea de comandos. + +El control de errores es nulo. Cualquier error de conexÃón con `geth` producirá un _stacktrace_. + +``` +bfa@bootnode:~$ bfa/src/sealer_status.py --help +usage: sealer_status.py [-h] [-n N] [-b] [--ipc-path IPC_PATH] + [--rpc-port RPC_PORT] + +Muestra la cantidad de bloques transcurridos desde la ultima aparición de cada +uno de los selladores de la BFA. Si un sellador no ha aparecido por un cierto +tiempo (por default 1 hora) imprime -1. + +optional arguments: + -h, --help show this help message and exit + -n N Máxima cantidad de bloques a recorrer. Default: 720 (1 + hora) + -b, --blockNumber Muestra el número de bloque en lugar de la cantidad de + bloques transcurridos + --ipc-path IPC_PATH Path del archivo geth.ipc. Default: + /home/bfa/bfa/network/node/geth.ipc + --rpc-port RPC_PORT Puerto RPC. Default: 8545 +bfa@bootnode:~$ bfa/src/sealer_status.py +c0310a7b3b25f49b11b: 0 +9b3ac6719b02ec7bb48: 1 +46991ada2a2544468eb: 2 +39170a1ce03729d141d: 3 +91c055c6478bd0ad6d1: 4 +609043ebde4a06bd28a: 5 +19fe7b9b3a1bebde77c: 6 +2feb6a8876bd9e2116b: 9 +998c2651db6f76ca568: 10 +342e1d075d820ed3f9d: -1 +(web3py) bfa@bfa-3:~$ bfa/src/sealer_status.py -b +998c2651db6f76ca568: 466927 +c0310a7b3b25f49b11b: 466926 +9b3ac6719b02ec7bb48: 466925 +46991ada2a2544468eb: 466924 +39170a1ce03729d141d: 466923 +91c055c6478bd0ad6d1: 466922 +609043ebde4a06bd28a: 466921 +19fe7b9b3a1bebde77c: 466920 +2feb6a8876bd9e2116b: 466917 +342e1d075d820ed3f9d: -1 +bfa@bootnode:~$ \ No newline at end of file diff --git a/sealer_status/sealer_status.js b/sealer_status/sealer_status.js new file mode 100644 index 0000000..bc33c2a --- /dev/null +++ b/sealer_status/sealer_status.js @@ -0,0 +1,45 @@ +function vanity2address(vanity){ + var address = ""; + for (i = 0; i < 38; i+=2) + address += String.fromCharCode(parseInt(vanity.substr(i,2),16)); + return address; +} + +function address2vanity(address){ + var vanity = ""; + for (i = 0; i < 19; i++) + vanity += address.charCodeAt(i).toString(16); + return vanity; +} + +function blockSigner(blockNumber){ + return eth.getBlock(blockNumber).extraData.substr(2,38); +} + + +function getSigners(){ + var signers = clique.getSigners(); + var dict = {}; + for (var i = 0; i < signers.length; i++){ + dict[address2vanity(signers[i].substr(2,19))] = true; + } + return dict; +} + +function lastSeen(){ + var signers = getSigners(); + var last = eth.blockNumber; + for(var i = 0; i < 720; i++){ + if (Object.keys(signers).length == 0) break; + var block = last - i; + var signer = blockSigner(block); + if (signer in signers){ + console.log(vanity2address(signer)+": "+block); + delete signers[signer]; + } + } + for (signer in signers) + console.log(vanity2address(signer)+": -1"); +} + +lastSeen(); diff --git a/sealer_status/sealer_status.py b/sealer_status/sealer_status.py new file mode 100755 index 0000000..1c6d806 --- /dev/null +++ b/sealer_status/sealer_status.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +from os import environ +ipc_path = "{}/node/geth.ipc".format(environ.get('BFANETWORKDIR', "~/bfa/network")) +rpc_port = 8545 +rpc_host = "localhost" +import requests +from web3 import Web3, IPCProvider +from web3.middleware import geth_poa_middleware +import argparse + + +def getSigners(): + session = requests.Session() + payload = {"jsonrpc":"2.0", "method":'clique_getSigners',"params":[],"id":1} + headers = {'Content-type':'application/json'} + response = session.post( + "http://{}:{}".format(rpc_host,rpc_port), + json=payload, + headers=headers) + return response.json()['result'] + +def lastSeen(n = 720, use_block_number = False): + last = w3.eth.blockNumber + signers = set(map(lambda x: x[2:21],getSigners())) + for i in range(n): + if not signers: break + block = last - i + address = w3.eth.getBlock(block).proofOfAuthorityData[:19].decode('ascii') + if address in signers: + print("{}: {}".format(address, block if use_block_number else i)) + signers.remove(address) + for address in signers: + print("{}: -1".format(address)) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description= + """Muestra la cantidad de bloques transcurridos desde la ultima aparición + de cada uno de los selladores de la BFA. Si un sellador no ha aparecido por + un cierto tiempo (por default 1 hora) imprime -1.""") + parser.add_argument("-n", help='Máxima cantidad de bloques a recorrer. Default: 720 (1 hora)',type=int, default=720) + parser.add_argument("-b", "--blockNumber", help="Muestra el número de bloque en lugar de la cantidad de bloques transcurridos", action="store_true") + parser.add_argument("--ipc-path", help ="Path del archivo geth.ipc. Default: {}".format(ipc_path)) + parser.add_argument("--rpc-port", help ="Puerto RPC. Default: {}".format(rpc_port),type=int) + args = parser.parse_args() + if args.ipc_path: + ipc_path = args.ipc_path + if args.rpc_port: + rpc_port = args.rpc_port + w3 = Web3(Web3.IPCProvider(ipc_path)) + w3.middleware_stack.inject(geth_poa_middleware, layer=0) + lastSeen(args.n, args.blockNumber) -- GitLab