new file: mmnode-feeview
modified: README.md renamed: mmnode-halving-calculator.py -> mmnode-halving-calculator This commit requires an updated mmgen installation
This commit is contained in:
parent
a320a084fb
commit
5c9437cd70
4 changed files with 232 additions and 7 deletions
18
README.md
18
README.md
|
|
@ -1,12 +1,20 @@
|
|||
# MMGen node tools
|
||||
|
||||
Optional helper programs for the [MMGen online/offline Bitcoin wallet][6]
|
||||
Helper utilities for Bitcoin and forkcoin full nodes.
|
||||
|
||||
Included in: https://github.com/mmgen/MMGenLive
|
||||
Requires modules from the [MMGen online/offline cryptocurrency wallet][6].
|
||||
|
||||
Requires: https://github.com/mmgen/mmgen
|
||||
Currently tested on Linux only. Some scripts may not work under Windows/MSYS2.
|
||||
|
||||
The node tools are Linux-only for now
|
||||
## Install:
|
||||
|
||||
First, install [MMGen][6].
|
||||
|
||||
Then,
|
||||
|
||||
$ git clone https://github.com/mmgen/mmgen-node-tools
|
||||
$ cd mmgen-node-tools
|
||||
$ sudo ./setup.py install
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
|
@ -15,5 +23,5 @@ The node tools are Linux-only for now
|
|||
Donate: 15TLdmi5NYLdqmtCqczUs5pBPkJDXRs83w
|
||||
|
||||
[4]: https://bitcointalk.org/index.php?topic=567069.0
|
||||
[5]: https://github.com/mmgen/mmgen/wiki/MMGen-Signing-Key
|
||||
[5]: https://github.com/mmgen/mmgen/wiki/MMGen-Signing-Keys
|
||||
[6]: https://github.com/mmgen/mmgen/
|
||||
|
|
|
|||
215
mmnode-feeview
Executable file
215
mmnode-feeview
Executable file
|
|
@ -0,0 +1,215 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2020 The MMGen Project <mmgen@tuta.io>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
mmnode-feeview: Visualize the fee structure of a node’s mempool
|
||||
"""
|
||||
|
||||
from mmgen.common import *
|
||||
|
||||
min_prec,max_prec,dfl_prec = (0,6,2)
|
||||
fee_brackets = [
|
||||
1, 2, 3, 4, 5, 6,
|
||||
8, 10, 12, 14, 16, 18,
|
||||
20, 25, 30, 35, 40, 45,
|
||||
50, 60, 70, 80, 90,
|
||||
100, 120, 140, 160, 180,
|
||||
200, 250, 300, 350, 400, 450,
|
||||
500, 600, 700, 800, 900,
|
||||
1000, 1200, 1400, 1600, 1800,
|
||||
2000, 2500, 3000, 3500, 4000, 4500,
|
||||
5000, 6000, 7000, 8000, 9000,
|
||||
10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000,
|
||||
100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 2100000000000000,
|
||||
]
|
||||
|
||||
opts.init({
|
||||
'sets': [
|
||||
('detail',True,'ranges',True),
|
||||
('detail',True,'show_mb_col',True),
|
||||
('detail',True,'precision',6),
|
||||
],
|
||||
'text': {
|
||||
'desc': 'Visualize the fee structure of a node’s mempool',
|
||||
'usage':'[opts]',
|
||||
'options': f"""
|
||||
-h, --help Print this help message
|
||||
--, --longhelp Print help message for long options (common options)
|
||||
-c, --include-current Include current bracket’s TXs in cumulative MB value
|
||||
-d, --detail Same as --ranges --show-mb-col --precision=6
|
||||
-e, --show-empty Show all fee brackets, including empty ones
|
||||
-i, --ignore-below=B Ignore fee brackets with less than 'B' bytes of TXs
|
||||
-l, --log Log JSON-RPC mempool data to 'mempool.json'
|
||||
-p, --precision=P Use 'P' decimal points of precision for megabyte amts
|
||||
(min: {min_prec}, max: {max_prec}, default: {dfl_prec})
|
||||
-r, --ranges Display fee brackets as ranges
|
||||
-s, --show-mb-col Display column with each fee bracket’s megabyte count
|
||||
-w, --width=W Force output width of 'W' columns (default: term width)
|
||||
""",
|
||||
'notes': """
|
||||
+ By default, fee bracket row labels include only the top of the range.
|
||||
+ By default, empty fee brackets are not displayed.
|
||||
+ Mempool amounts are shown in decimal megabytes.
|
||||
+ Values in the Total MB column are cumulative and represent megabytes of
|
||||
transactions in the mempool with fees higher than the TOP of the current
|
||||
fee bracket. To change this behavior, use the --include-current option.
|
||||
|
||||
Note that there is no global mempool in Bitcoin, and your node’s mempool may
|
||||
differ significantly from those of mining nodes depending on uptime and other
|
||||
factors.
|
||||
"""
|
||||
}
|
||||
})
|
||||
|
||||
if opt.ignore_below:
|
||||
if opt.show_empty:
|
||||
die(1,'Conflicting options: --ignore-below, --show-empty')
|
||||
ignore_below = parse_bytespec(opt.ignore_below)
|
||||
|
||||
if opt.precision:
|
||||
precision = check_int_between(opt.precision,min_prec,max_prec,'--precision arg')
|
||||
else:
|
||||
precision = dfl_prec
|
||||
|
||||
if opt.width:
|
||||
width = check_int_between(opt.width,40,1024,'--width arg')
|
||||
else:
|
||||
from mmgen.term import get_terminal_size
|
||||
width = get_terminal_size()[0]
|
||||
|
||||
class fee_bracket:
|
||||
def __init__(self,top,bottom):
|
||||
self.top = top
|
||||
self.bottom = bottom
|
||||
self.tx_bytes = 0
|
||||
self.tx_bytes_cum = 0
|
||||
self.skip = False
|
||||
|
||||
def get_fake_data(fn): # for debugging
|
||||
import json
|
||||
from mmgen.rpc import json_encoder
|
||||
from decimal import Decimal
|
||||
return json.loads(open(os.path.join(fn)).read(),parse_float=Decimal)
|
||||
|
||||
def log(data,fn):
|
||||
import json
|
||||
from mmgen.rpc import json_encoder
|
||||
open(fn,'w').write(json.dumps(data,cls=json_encoder,sort_keys=True,indent=4))
|
||||
|
||||
def create_data(coin_amt,mempool):
|
||||
out = [fee_bracket(fee_brackets[i],fee_brackets[i-1] if i else 0) for i in range(len(fee_brackets))]
|
||||
|
||||
# populate fee brackets:
|
||||
for tx in mempool.values():
|
||||
fee = coin_amt(tx['fee']).toSatoshi()
|
||||
vsize = tx['vsize']
|
||||
for bracket in out:
|
||||
if fee / vsize < bracket.top:
|
||||
bracket.tx_bytes += vsize
|
||||
break
|
||||
|
||||
# remove empty top brackets:
|
||||
while out[-1].tx_bytes == 0:
|
||||
out.pop()
|
||||
|
||||
out.reverse() # cumulative totals and display are top-down
|
||||
|
||||
# calculate cumulative byte totals, filter rows:
|
||||
tBytes = 0
|
||||
for i in out:
|
||||
if not (i.tx_bytes or opt.show_empty):
|
||||
i.skip = True
|
||||
if opt.ignore_below and i.tx_bytes < ignore_below:
|
||||
i.skip = True
|
||||
i.tx_bytes_cum = tBytes
|
||||
tBytes += i.tx_bytes
|
||||
|
||||
return out
|
||||
|
||||
def print_header(host,blockcount):
|
||||
print('MEMPOOL FEE STRUCTURE ({})\n{} UTC\nBlock {}'.format(
|
||||
host,
|
||||
make_timestr(),
|
||||
blockcount,
|
||||
))
|
||||
if opt.show_empty:
|
||||
print('Displaying all fee brackets')
|
||||
elif opt.ignore_below:
|
||||
print('Ignoring fee brackets with less than {} bytes ({})'.format(
|
||||
ignore_below,
|
||||
int2bytespec(ignore_below,'MB','0.6'),
|
||||
))
|
||||
if opt.include_current:
|
||||
print('Including transactions in current fee bracket in Total MB amounts')
|
||||
|
||||
def fmt_mb(n):
|
||||
return int2bytespec(n,'MB',f'0.{precision}',False)
|
||||
|
||||
def print_body(data):
|
||||
tx_bytes_max = max(i.tx_bytes for i in data)
|
||||
top_max = max(i.top for i in data if not i.skip)
|
||||
bot_max = max(i.bottom for i in data if not i.skip)
|
||||
col1_w = max(len(f'{bot_max}-{top_max}') if opt.ranges else len(f'{top_max}'),6)
|
||||
col2_w = len(fmt_mb(tx_bytes_max)) if opt.show_mb_col else 0
|
||||
col3_w = len(fmt_mb(data[-1].tx_bytes_cum))
|
||||
col4_w = width - col1_w - col2_w - col3_w - (4 if col2_w else 3)
|
||||
if opt.show_mb_col:
|
||||
fs = '{a:<%i} {b:>%i} {c:>%i} {d}' % (col1_w,col2_w,col3_w)
|
||||
else:
|
||||
fs = '{a:<%i} {c:>%i} {d}' % (col1_w,col3_w)
|
||||
|
||||
print(
|
||||
'\n' + fs.format(a='', b='', c=f'{"Total":<{col3_w}}', d='') +
|
||||
'\n' + fs.format(a='sat/B', b=f'{"MB":<{col2_w}}', c=f'{"MB":<{col3_w}}', d='')
|
||||
)
|
||||
|
||||
for i in data:
|
||||
if not i.skip:
|
||||
cum_bytes = i.tx_bytes_cum + i.tx_bytes if opt.include_current else i.tx_bytes_cum
|
||||
print(fs.format(
|
||||
a = '{}-{}'.format(i.bottom,i.top) if opt.ranges else i.top,
|
||||
b = fmt_mb(i.tx_bytes),
|
||||
c = fmt_mb(cum_bytes),
|
||||
d = '-' * int(col4_w * ( i.tx_bytes / tx_bytes_max )) ))
|
||||
|
||||
print(fs.format(
|
||||
a = 'TOTAL',
|
||||
b = '',
|
||||
c = fmt_mb(data[-1].tx_bytes_cum + data[-1].tx_bytes),
|
||||
d = '' ))
|
||||
|
||||
async def main():
|
||||
|
||||
from mmgen.protocol import init_proto_from_opts
|
||||
proto = init_proto_from_opts()
|
||||
|
||||
from mmgen.rpc import rpc_init
|
||||
c = await rpc_init(proto)
|
||||
|
||||
# pmsg(await c.call('getmempoolinfo'))
|
||||
mempool = await c.call('getrawmempool',True)
|
||||
# mempool = get_fake_data('test_data/mempool-sample.json')
|
||||
|
||||
if opt.log:
|
||||
log(mempool,'mempool.json')
|
||||
|
||||
data = create_data(proto.coin_amt,mempool)
|
||||
print_header(c.host,await c.call('getblockcount'))
|
||||
print_body(data)
|
||||
|
||||
run_session(main())
|
||||
6
setup.py
6
setup.py
|
|
@ -40,10 +40,12 @@ setup(
|
|||
keywords = g.keywords,
|
||||
packages = ['mmgen.node_tools'],
|
||||
scripts = [
|
||||
'mmnode-play-sound',
|
||||
'mmnode-blocks-info',
|
||||
'mmnode-feeview',
|
||||
'mmnode-halving-calculator',
|
||||
'mmnode-netrate',
|
||||
'mmnode-peerblocks',
|
||||
'mmnode-blocks-info',
|
||||
'mmnode-play-sound',
|
||||
],
|
||||
data_files = [('share/mmgen/node_tools/audio', [
|
||||
'data_files/audio/ringtone.wav', # source files must have 0644 mode
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue