mirror of
https://github.com/romanz/electrs.git
synced 2024-11-19 01:43:29 +01:00
Rewrite Python scripts
Also, improve balance/history display
This commit is contained in:
parent
b9e8aa8e7c
commit
423e4c7922
@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import hashlib
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
import client
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--testnet', action='store_true')
|
||||
parser.add_argument('address', nargs='+')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.testnet:
|
||||
port = 60001
|
||||
from pycoin.symbols.xtn import network
|
||||
else:
|
||||
port = 50001
|
||||
from pycoin.symbols.btc import network
|
||||
|
||||
conn = client.Client(('localhost', port))
|
||||
for addr in args.address:
|
||||
script = network.parse.address(addr).script()
|
||||
script_hash = hashlib.sha256(script).digest()[::-1].hex()
|
||||
reply = conn.call('blockchain.scripthash.subscribe', script_hash)
|
||||
print(f'{reply}')
|
||||
reply = conn.call('blockchain.scripthash.get_history', script_hash)
|
||||
result = reply['result']
|
||||
print(f'{addr} has {len(result)} transactions:')
|
||||
for tx in result:
|
||||
print(f'* {tx["tx_hash"]}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -7,16 +7,18 @@ class Client:
|
||||
self.f = self.s.makefile('r')
|
||||
self.id = 0
|
||||
|
||||
def request(self, method, *args):
|
||||
self.id += 1
|
||||
return {
|
||||
'id': self.id,
|
||||
'method': method,
|
||||
'params': list(args),
|
||||
'jsonrpc': '2.0',
|
||||
}
|
||||
def call(self, requests):
|
||||
requests = list(requests)
|
||||
for request in requests:
|
||||
request['id'] = self.id
|
||||
request['jsonrpc'] = '2.0'
|
||||
self.id += 1
|
||||
|
||||
def call(self, *requests):
|
||||
msg = json.dumps(requests) + '\n'
|
||||
self.s.sendall(msg.encode('ascii'))
|
||||
return json.loads(self.f.readline())
|
||||
response = json.loads(self.f.readline())
|
||||
return [r['result'] for r in response]
|
||||
|
||||
|
||||
def request(method, *args):
|
||||
return {'method': method, 'params': list(args)}
|
||||
|
@ -10,7 +10,7 @@ def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
conn = client.Client((args.host, args.port))
|
||||
print(conn.call(conn.request("blockchain.headers.subscribe"))[0]["result"])
|
||||
print(conn.call([client.request("blockchain.headers.subscribe")]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -9,7 +9,7 @@ def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
conn = client.Client(("localhost", 50001))
|
||||
tx = conn.call("blockchain.transaction.get", args.txid, True)["result"]
|
||||
tx, = conn.call([client.request("blockchain.transaction.get", args.txid, True)])
|
||||
print(json.dumps(tx))
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -10,7 +10,7 @@ def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
conn = client.Client((args.host, args.port))
|
||||
print(json.dumps(conn.call("server.version", "health_check", "1.4")["result"]))
|
||||
print(json.dumps(conn.call([client.request("server.version", "health_check", "1.4")])))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
132
contrib/history.py
Executable file
132
contrib/history.py
Executable file
@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import datetime
|
||||
import hashlib
|
||||
import io
|
||||
import sys
|
||||
|
||||
import pycoin
|
||||
from logbook import Logger, StreamHandler
|
||||
import prettytable
|
||||
|
||||
import client
|
||||
|
||||
log = Logger('electrum')
|
||||
|
||||
|
||||
def _script_hash(script):
|
||||
return hashlib.sha256(script).digest()[::-1].hex()
|
||||
|
||||
|
||||
def show_rows(rows, field_names):
|
||||
t = prettytable.PrettyTable()
|
||||
t.field_names = field_names
|
||||
t.add_rows(rows)
|
||||
for f in t.field_names:
|
||||
if "mBTC" in f:
|
||||
t.align[f] = "r"
|
||||
print(t)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--testnet', action='store_true')
|
||||
parser.add_argument('address', nargs='+')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.testnet:
|
||||
port = 60001
|
||||
from pycoin.symbols.xtn import network
|
||||
else:
|
||||
port = 50001
|
||||
from pycoin.symbols.btc import network
|
||||
|
||||
hostport = ('localhost', port)
|
||||
log.info('connecting to {}:{}', *hostport)
|
||||
conn = client.Client(hostport)
|
||||
|
||||
tip, = conn.call([client.request('blockchain.headers.subscribe')])
|
||||
|
||||
script_hashes = set(
|
||||
_script_hash(network.parse.address(addr).script())
|
||||
for addr in args.address
|
||||
)
|
||||
|
||||
conn.call(
|
||||
client.request('blockchain.scripthash.subscribe', script_hash)
|
||||
for script_hash in script_hashes
|
||||
)
|
||||
log.info('subscribed to {} scripthashes', len(script_hashes))
|
||||
|
||||
histories = conn.call(
|
||||
client.request('blockchain.scripthash.get_history', script_hash)
|
||||
for script_hash in script_hashes
|
||||
)
|
||||
txids_map = dict(
|
||||
(tx['tx_hash'], tx['height'] if tx['height'] > 0 else None)
|
||||
for history in histories
|
||||
for tx in history
|
||||
)
|
||||
log.info('got history of {} transactions', len(txids_map))
|
||||
|
||||
txs = map(network.tx.from_hex, conn.call(
|
||||
client.request('blockchain.transaction.get', txid)
|
||||
for txid in txids_map.keys()
|
||||
))
|
||||
txs_map = dict(zip(txids_map.keys(), txs))
|
||||
log.info('loaded {} transactions', len(txids_map))
|
||||
|
||||
confirmed_txids = {txid: height for txid, height in txids_map.items() if height is not None}
|
||||
|
||||
heights = set(confirmed_txids.values())
|
||||
def _parse_header(header):
|
||||
return network.block.parse_as_header(io.BytesIO(bytes.fromhex(header)))
|
||||
headers = map(_parse_header, conn.call(
|
||||
client.request('blockchain.block.header', height)
|
||||
for height in heights
|
||||
))
|
||||
def _parse_timestamp(header):
|
||||
return datetime.datetime.utcfromtimestamp(header.timestamp).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
timestamps = map(_parse_timestamp, headers)
|
||||
timestamps_map = dict(zip(heights, timestamps))
|
||||
log.info('loaded {} header timestamps', len(heights))
|
||||
|
||||
proofs = conn.call(
|
||||
client.request('blockchain.transaction.get_merkle', txid, height)
|
||||
for txid, height in confirmed_txids.items()
|
||||
)
|
||||
log.info('loaded {} merkle proofs', len(proofs)) # TODO: verify proofs
|
||||
|
||||
sorted_txdata = sorted(
|
||||
(proof['block_height'], proof['pos'], txid)
|
||||
for proof, txid in zip(proofs, confirmed_txids)
|
||||
)
|
||||
|
||||
utxos = {}
|
||||
balance = 0
|
||||
|
||||
rows = []
|
||||
for block_height, block_pos, txid in sorted_txdata:
|
||||
tx_obj = txs_map[txid]
|
||||
for txi in tx_obj.txs_in:
|
||||
utxos.pop((str(txi.previous_hash), txi.previous_index), None)
|
||||
|
||||
for index, txo in enumerate(tx_obj.txs_out):
|
||||
if _script_hash(txo.puzzle_script()) in script_hashes:
|
||||
utxos[(txid, index)] = txo
|
||||
|
||||
diff = sum(txo.coin_value for txo in utxos.values()) - balance
|
||||
balance += diff
|
||||
confirmations = tip['height'] - block_height + 1
|
||||
rows.append([txid, timestamps_map[block_height], block_height, confirmations, f'{diff/1e5:,.5f}', f'{balance/1e5:,.5f}'])
|
||||
show_rows(rows, ["txid", "block timestamp", "height", "confirmations", "delta (mBTC)", "total (mBTC)"])
|
||||
|
||||
tip_header = _parse_header(tip['hex'])
|
||||
log.info('tip={}, height={} @ {}', tip_header.id(), tip['height'], _parse_timestamp(tip_header))
|
||||
|
||||
unconfirmed = {txs_map[txid] for txid, height in txids_map.items() if height is None}
|
||||
# TODO: show unconfirmed balance
|
||||
|
||||
if __name__ == '__main__':
|
||||
StreamHandler(sys.stderr).push_application()
|
||||
main()
|
4
contrib/history.sh
Executable file
4
contrib/history.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
cd `dirname $0`
|
||||
.env/bin/python history.py $*
|
@ -8,15 +8,14 @@ def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
conn = client.Client(("localhost", 50001))
|
||||
tx = conn.call(conn.request("blockchain.transaction.get", args.txid, True))[0]["result"]
|
||||
tx, = conn.call([client.request("blockchain.transaction.get", args.txid, True)])
|
||||
requests = []
|
||||
for vin in tx["vin"]:
|
||||
prev_txid = vin["txid"]
|
||||
requests.append(conn.request("blockchain.transaction.get", prev_txid, True))
|
||||
requests.append(client.request("blockchain.transaction.get", prev_txid, True))
|
||||
|
||||
fee = 0
|
||||
for vin, response in zip(tx["vin"], conn.call(*requests)):
|
||||
prev_tx = response["result"]
|
||||
for vin, prev_tx in zip(tx["vin"], conn.call(requests)):
|
||||
txo = prev_tx["vout"][vin["vout"]]
|
||||
fee += txo["value"]
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
trap 'kill $(jobs -p)' EXIT
|
||||
|
||||
DELAY=5
|
||||
LOG=/tmp/electrs.log
|
||||
CARGO="cargo +stable"
|
||||
|
||||
tail -v -n0 -F "$LOG" &
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
while :
|
||||
do
|
||||
$CARGO fmt
|
||||
$CARGO check --release
|
||||
$CARGO run --release -- $* 2>> "$LOG"
|
||||
echo "Restarting in $DELAY seconds..."
|
||||
sleep $DELAY
|
||||
done
|
Loading…
Reference in New Issue
Block a user