forked from chromaway/ngcccbase
-
Notifications
You must be signed in to change notification settings - Fork 0
/
colordata.py
132 lines (110 loc) · 5.27 KB
/
colordata.py
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
""" Color data representation objects."""
import time
from colordef import ColorDefinition
from colorvalue import SimpleColorValue
class UnfoundTransactionError(Exception):
pass
class ColorData(object):
"""Base color data class"""
pass
class StoredColorData(ColorData):
def __init__(self, cdbuilder_manager, blockchain_state, cdstore, colormap):
self.cdbuilder_manager = cdbuilder_manager
self.blockchain_state = blockchain_state
self.cdstore = cdstore
self.colormap = colormap
def _fetch_colorvalues(self, color_id_set, txhash, outindex,
cvclass=SimpleColorValue):
"""returns colorvalues currently present in cdstore"""
ret = []
for entry in self.cdstore.get_any(txhash, outindex):
color_id, value, label = entry
if color_id in color_id_set:
color_def = self.colormap.get_color_def(color_id)
ret.append(cvclass(colordef=color_def, value=value,
label=label))
return ret
def get_colorvalues_raw(self, color_id, ctx):
"""get colorvalues for all outputs of a raw transaction
(which is, possibly, not in the blockchain yet)
"""
color_id_set = set([color_id])
color_def = self.cdbuilder_manager.colormap.get_color_def(color_id)
in_colorvalues = []
for inp in ctx.inputs:
cvs = self.get_colorvalues(color_id_set,
inp.prevout.hash,
inp.prevout.n)
cv = cvs[0] if cvs else None
in_colorvalues.append(cv)
return color_def.run_kernel(ctx, in_colorvalues)
class ThickColorData(StoredColorData):
""" Color data which needs access to the whole blockchain state"""
def __init__(self, *args, **kwargs):
super(ThickColorData, self).__init__(*args, **kwargs)
self.mempool_cache = []
def get_colorvalues(self, color_id_set, txhash, outindex):
blockhash, found = self.blockchain_state.get_tx_blockhash(txhash)
if not found:
raise UnfoundTransactionError("Transaction %s not found!" % txhash)
if blockhash:
self.cdbuilder_manager.ensure_scanned_upto(color_id_set, blockhash)
return self._fetch_colorvalues(color_id_set, txhash, outindex)
else:
# not in the blockchain, but might be in the memory pool
best_blockhash = None
while 1:
best_blockhash_prev = self.blockchain_state.get_best_blockhash()
mempool = self.blockchain_state.get_mempool_txs()
best_blockhash = self.blockchain_state.get_best_blockhash()
if best_blockhash_prev == best_blockhash:
break
if txhash not in [tx.hash for tx in mempool]:
raise UnfoundTransactionError("Transaction %s not found in mempool!" % txhash)
# the preceding blockchain
self.cdbuilder_manager.ensure_scanned_upto(
color_id_set, best_blockhash)
# scan everything in the mempool
for tx in mempool:
self.cdbuilder_manager.scan_tx(color_id_set, tx)
return self._fetch_colorvalues(color_id_set, txhash, outindex)
class ThinColorData(StoredColorData):
""" Color data which needs access to the blockchain state up to the genesis of
color."""
def get_colorvalues(self, color_id_set, txhash, outindex):
"""
for a given transaction <txhash> and output <outindex> and color
<color_id_set>, return a list of dicts that looks like this:
{
'color_id': <color id>,
'value': <colorvalue of this output>,
'label': <currently unused>,
}
These correspond to the colorvalues of particular color ids for this
output. Currently, each output should have a single element in the list.
"""
color_def_map = self.cdbuilder_manager.get_color_def_map(color_id_set)
scanned_outputs = set()
def process(current_txhash, current_outindex):
"""For any tx out, process the colorvalues of the affecting
inputs first and then scan that tx.
"""
if (current_txhash, current_outindex) in scanned_outputs:
return
scanned_outputs.add((current_txhash, current_outindex))
if self._fetch_colorvalues(color_id_set, current_txhash, current_outindex):
return
current_tx = self.blockchain_state.get_tx(current_txhash)
if not current_tx:
raise UnfoundTransactionError("Transaction %s not found!" % current_txhash)
# note a genesis tx will simply have 0 affecting inputs
inputs = set()
for color_id, color_def in color_def_map.items():
inputs = inputs.union(
color_def.get_affecting_inputs(current_tx,
[current_outindex]))
for i in inputs:
process(i.prevout.hash, i.prevout.n)
self.cdbuilder_manager.scan_tx(color_id_set, current_tx, [current_outindex])
process(txhash, outindex)
return self._fetch_colorvalues(color_id_set, txhash, outindex)