From b33b570704aa46baffec25e9cc1f248083d29a89 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 3 Aug 2019 14:46:39 +0300 Subject: [PATCH] Add a script for computing tx fee --- contrib/addr.py | 2 +- contrib/client.py | 2 +- contrib/daemon.py | 41 +++++++++++++++++++++++++++++++++++++++++ contrib/mempool.py | 42 ++---------------------------------------- contrib/tx_fee.py | 33 +++++++++++++++++++++++++++++++++ contrib/xpub.py | 2 +- 6 files changed, 79 insertions(+), 43 deletions(-) create mode 100644 contrib/daemon.py create mode 100755 contrib/tx_fee.py diff --git a/contrib/addr.py b/contrib/addr.py index 326b900..da36c56 100755 --- a/contrib/addr.py +++ b/contrib/addr.py @@ -20,7 +20,7 @@ def main(): Network = BitcoinMainnet port = 50001 - conn = client.Connection(('localhost', port)) + conn = client.Client(('localhost', port)) for addr in args.address: script = Network.ui.script_for_address(addr) script_hash = hashlib.sha256(script).digest()[::-1].hex() diff --git a/contrib/client.py b/contrib/client.py index d47a921..17ce913 100644 --- a/contrib/client.py +++ b/contrib/client.py @@ -1,7 +1,7 @@ import json import socket -class Connection: +class Client: def __init__(self, addr): self.s = socket.create_connection(addr) self.f = self.s.makefile('r') diff --git a/contrib/daemon.py b/contrib/daemon.py new file mode 100644 index 0000000..85c7351 --- /dev/null +++ b/contrib/daemon.py @@ -0,0 +1,41 @@ +import binascii +import json +import os +import socket + + +class Daemon: + def __init__(self, port, cookie_dir): + self.sock = socket.create_connection(('localhost', port)) + self.fd = self.sock.makefile() + path = os.path.join(os.path.expanduser(cookie_dir), '.cookie') + cookie = binascii.b2a_base64(open(path, 'rb').read()) + self.cookie = cookie.decode('ascii').strip() + self.index = 0 + + def request(self, method, params_list): + obj = [{"method": method, "params": params, "id": self.index} + for params in params_list] + request = json.dumps(obj) + + msg = ('POST / HTTP/1.1\n' + 'Authorization: Basic {}\n' + 'Content-Length: {}\n\n' + '{}'.format(self.cookie, len(request), request)) + self.sock.sendall(msg.encode('ascii')) + + status = self.fd.readline().strip() + while True: + if self.fd.readline().strip(): + continue # skip headers + else: + break # next line will contain the response + + data = self.fd.readline().strip() + replies = json.loads(data) + for reply in replies: + assert reply['error'] is None, reply + assert reply['id'] == self.index + + self.index += 1 + return [d['result'] for d in replies] diff --git a/contrib/mempool.py b/contrib/mempool.py index 987aa2a..f5d7486 100755 --- a/contrib/mempool.py +++ b/contrib/mempool.py @@ -1,49 +1,11 @@ #!/usr/bin/env python3 + import argparse -import binascii -import json -import os -import socket +from daemon import Daemon import numpy as np import matplotlib.pyplot as plt -class Daemon: - def __init__(self, port, cookie_dir): - self.sock = socket.create_connection(('localhost', port)) - self.fd = self.sock.makefile() - path = os.path.join(os.path.expanduser(cookie_dir), '.cookie') - cookie = binascii.b2a_base64(open(path, 'rb').read()) - self.cookie = cookie.decode('ascii').strip() - self.index = 0 - - def request(self, method, params_list): - obj = [{"method": method, "params": params, "id": self.index} - for params in params_list] - request = json.dumps(obj) - - msg = ('POST / HTTP/1.1\n' - 'Authorization: Basic {}\n' - 'Content-Length: {}\n\n' - '{}'.format(self.cookie, len(request), request)) - self.sock.sendall(msg.encode('ascii')) - - status = self.fd.readline().strip() - while True: - if self.fd.readline().strip(): - continue # skip headers - else: - break # next line will contain the response - - data = self.fd.readline().strip() - replies = json.loads(data) - for reply in replies: - assert reply['error'] is None - assert reply['id'] == self.index - - self.index += 1 - return [d['result'] for d in replies] - def main(): parser = argparse.ArgumentParser() diff --git a/contrib/tx_fee.py b/contrib/tx_fee.py new file mode 100755 index 0000000..7af4b22 --- /dev/null +++ b/contrib/tx_fee.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +import argparse +import daemon + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('txid') + args = parser.parse_args() + + d = daemon.Daemon(port=8332, cookie_dir='~/.bitcoin') + txid = args.txid + + txn, = d.request('getrawtransaction', [[txid, True]]) + vin = txn['vin'] + + fee = 0.0 + for txi in txn['vin']: + prev_txid = txi['txid'] + prev_tx, = d.request('getrawtransaction', [[prev_txid, True]]) + index = txi['vout'] + prev_txo = prev_tx['vout'][index] + print(f"{prev_txid}:{index:<5} {prev_txo['value']:+20.8f}") + fee += prev_txo['value'] + + for i, txo in enumerate(txn['vout']): + print(f"{txid}:{i:<5} {-txo['value']:+20.8f}") + fee -= txo['value'] + + print(f"Fee = {1e6 * fee:.2f} uBTC = {1e8 * fee / txn['vsize']:.2f} sat/vB") + +if __name__ == '__main__': + main() diff --git a/contrib/xpub.py b/contrib/xpub.py index cfab863..4ed6e19 100755 --- a/contrib/xpub.py +++ b/contrib/xpub.py @@ -15,7 +15,7 @@ script_for_address = BitcoinMainnet.ui.script_for_address log = Logger(__name__) def main(): - conn = client.Connection(('localhost', 50001)) + conn = client.Client(('localhost', 50001)) xpub, = sys.argv[1:] total = 0 k = pycoin.ui.key_from_text.key_from_text(xpub)