forked from hyperledger/indy-node
-
Notifications
You must be signed in to change notification settings - Fork 0
/
read_ledger
executable file
·205 lines (166 loc) · 6.95 KB
/
read_ledger
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#! /usr/bin/env python3
"""
Convenience script for reading a ledger transaction data (stored in leveldb)
"""
import argparse
import logging
import os
import shutil
from pathlib import Path
from common.serializers.json_serializer import JsonSerializer
from plenum.common.ledger import Ledger
from plenum.common.constants import HS_ROCKSDB
from indy_common.config_util import getConfig
from indy_common.config_helper import ConfigHelper, NodeConfigHelper
from common.serializers.serialization import ledger_txn_serializer
logging.root.handlers = []
logger = logging.getLogger()
logger.propagate = False
logger.disabled = True
_DATA = 'data'
# TODO: Replace with constant from config
postfix = '_transactions'
def read_args():
parser = argparse.ArgumentParser(
description="Read ledger transactions")
parser.add_argument('--type', required=True,
help='Ledger type (pool, domain, config)')
parser.add_argument(
'--frm',
required=False,
default=None,
help="read all transactions starting from (beginning by default)")
parser.add_argument('--to', required=False, default=100,
help="read all transactions till (100 by default)")
parser.add_argument('--seq_no', required=False,
help="read a particular transaction")
parser.add_argument('--count', required=False, action='store_true',
help="returns the number of txns in the given ledger")
parser.add_argument('--node_name', required=False, help="Node's name")
parser.add_argument('--client_name', required=False, help="Client's name")
parser.add_argument('--serializer', required=False, default='json',
help="How to represent the data (json by default)")
parser.add_argument('--network', required=False, type=str,
help="Network name to read ledger from")
return parser.parse_args()
def get_ledger_dir(node_name, client_name, network):
if node_name and client_name:
print("Either 'node_name' or 'client_name' can be specified")
exit()
config = getConfig()
_network = network if network else config.NETWORK_NAME
ledger_base_dir = config.LEDGER_DIR
if client_name:
# Build path to data if --client_name was specified
ledger_data_dir = os.path.join(config.CLI_BASE_DIR, _network,
config.clientDataDir, client_name)
return ledger_data_dir
if node_name:
# Build path to data if --node_name was specified
ledger_data_dir = os.path.join(ledger_base_dir, _network, _DATA, node_name)
else:
ledger_data_dir = os.path.join(ledger_base_dir, _network, _DATA)
if os.path.exists(ledger_data_dir):
dirs = os.listdir(ledger_data_dir)
if len(dirs) == 0:
print("Node's 'data' folder not found: {}".format(ledger_data_dir))
exit()
# --node_name parameter was not set, therefore we can choose first Node name in data dir
ledger_data_dir = os.path.join(ledger_data_dir, dirs[0])
if not os.path.exists(ledger_data_dir):
print("No such file or directory: {}".format(ledger_data_dir))
print("Please check, that network: '{}' was used ".format(_network))
exit()
return ledger_data_dir
def get_storage(type_, ledger_data_dir):
config = getConfig()
storage_name = None
if type_ == 'pool':
storage_name = config.poolTransactionsFile
elif type_ == 'domain':
storage_name = config.domainTransactionsFile
elif type_ == 'config':
storage_name = config.configTransactionsFile
elif type_ in get_additional_storages(ledger_data_dir):
storage_name = type_ + postfix
else:
print("Unknown ledger type: {}".format(type_))
exit()
return Ledger._defaultStore(dataDir=ledger_data_dir,
logName=storage_name,
ensureDurability=True,
open=True,
config=config,
read_only=True)
def get_additional_storages(ledger_data_dir):
additional_storages = \
[name[:name.find(postfix)] for name in os.listdir(ledger_data_dir) if postfix in name]
return additional_storages
def print_txns(storage, args):
serializer = None
if args.serializer == 'json':
serializer = JsonSerializer()
else:
print("Unknown serializer for output: {}".format(args.serializer))
exit()
# --count
count = args.count
if count:
print_count(storage)
return
# --seq_no
seq_no = args.seq_no
if seq_no:
print_by_seq_no(storage, seq_no, serializer)
return
# print all (--from --to)
print_all(storage, serializer)
def print_by_seq_no(storage, seq_no, serializer):
try:
txn = storage.get(seq_no)
except KeyError:
print('No transactions found for seq_no={}'.format(seq_no))
return
txn = serializer.serialize(txn, toBytes=False)
print(txn)
return
def print_count(storage):
print(storage.size)
def print_all(storage, serializer):
frm = int(args.frm) if args.frm else None
to = int(args.to) if args.to else None
for seqNo, txn in storage.iterator(start=frm, end=to):
txn = ledger_txn_serializer.deserialize(txn)
print(serializer.serialize(txn, toBytes=False))
def make_copy_of_ledger(data_dir):
read_copy_data_dir = data_dir + '-read-copy'
if os.path.exists(read_copy_data_dir):
shutil.rmtree(read_copy_data_dir)
shutil.copytree(data_dir, read_copy_data_dir)
return read_copy_data_dir
if __name__ == '__main__':
args = read_args()
config = getConfig()
ledger_data_dir = get_ledger_dir(args.node_name, args.client_name, args.network)
read_copy_ledger_data_dir = None
try:
# RocksDB supports real read-only mode and does not need to have a ledger copy.
if config.hashStore['type'].lower() != HS_ROCKSDB:
config.db_transactions_config = None
# NOTE: such approach works well only for small ledgers.
tmp = make_copy_of_ledger(ledger_data_dir)
# Let's be paranoid to avoid removing of ledger instead of its copy.
ledger_path = Path(ledger_data_dir)
ledger_copy_path = Path(tmp)
assert ledger_path != ledger_copy_path
assert ledger_copy_path not in ledger_path.parents
read_copy_ledger_data_dir = tmp
ledger_data_dir = read_copy_ledger_data_dir
elif config.db_transactions_config is not None:
# This allows to avoid debug logs creation on each read_ledger run
config.db_transactions_config['db_log_dir'] = '/dev/null'
storage = get_storage(args.type, ledger_data_dir)
print_txns(storage, args)
finally:
if read_copy_ledger_data_dir:
shutil.rmtree(read_copy_ledger_data_dir)