OpReturnData -> DataOutput
This commit is contained in:
parent
73cf5814cf
commit
b794e26bd2
5 changed files with 32 additions and 24 deletions
|
|
@ -18,7 +18,7 @@ from ....tx.base import Base as TxBase
|
|||
from ....obj import MMGenList, HexStr, ListItemAttr
|
||||
from ....util import msg, make_chksum_6, die, pp_fmt
|
||||
|
||||
from .op_return_data import OpReturnData
|
||||
from .data_output import DataOutput
|
||||
|
||||
def data2scriptPubKey(data):
|
||||
return '6a' + '{:02x}'.format(len(data)) + data.hex() # OP_RETURN data
|
||||
|
|
@ -188,7 +188,7 @@ class Base(TxBase):
|
|||
_deserialized = None
|
||||
|
||||
class Output(TxBase.Output): # output contains either addr or data, but not both
|
||||
data = ListItemAttr(OpReturnData, include_proto=True) # type None in parent cls
|
||||
data = ListItemAttr(DataOutput, include_proto=True) # type None in parent cls
|
||||
|
||||
class InputList(TxBase.InputList):
|
||||
|
||||
|
|
|
|||
|
|
@ -9,38 +9,46 @@
|
|||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
proto.btc.tx.op_return_data: Bitcoin OP_RETURN data class
|
||||
proto.btc.tx.data_output: Bitcoin data output class
|
||||
"""
|
||||
|
||||
from ....obj import InitErrors
|
||||
|
||||
class OpReturnData(bytes, InitErrors):
|
||||
class DataOutput(bytes, InitErrors):
|
||||
|
||||
desc = 'OP_RETURN data'
|
||||
|
||||
@property
|
||||
def max_len(self):
|
||||
return self.proto.max_op_return_data_len
|
||||
|
||||
def __new__(cls, proto, data_spec):
|
||||
|
||||
desc = 'OP_RETURN data'
|
||||
|
||||
assert isinstance(data_spec, str), f'{desc} argument must be a string'
|
||||
assert isinstance(data_spec, str), f'{cls.desc} argument must be a string'
|
||||
|
||||
if data_spec.startswith('hexdata:'):
|
||||
hexdata = data_spec[8:]
|
||||
from ....util import is_hex_str
|
||||
assert is_hex_str(hexdata), f'{hexdata!r}: {desc} hexdata not in hexadecimal format'
|
||||
assert not len(hexdata) % 2, f'{len(hexdata)}: {desc} hexdata of non-even length'
|
||||
assert is_hex_str(hexdata), f'{hexdata!r}: {cls.desc} hexdata not in hexadecimal format'
|
||||
assert not len(hexdata) % 2, f'{len(hexdata)}: {cls.desc} hexdata of non-even length'
|
||||
ret = bytes.fromhex(hexdata)
|
||||
elif data_spec.startswith('data:'):
|
||||
try:
|
||||
ret = data_spec[5:].encode('utf8')
|
||||
except:
|
||||
raise ValueError(f'{desc} value must be UTF-8 encoded')
|
||||
raise ValueError(f'{cls.desc} value must be UTF-8 encoded')
|
||||
else:
|
||||
raise ValueError(f'{desc} argument must start with ‘data:’ or ‘hexdata:’')
|
||||
|
||||
assert 1 <= len(ret) <= proto.max_op_return_data_len, (
|
||||
f'{len(ret)}: invalid {desc} length: not in range 1-{proto.max_op_return_data_len}')
|
||||
raise ValueError(f'{cls.desc} argument must start with ‘data:’ or ‘hexdata:’')
|
||||
|
||||
return bytes.__new__(cls, ret)
|
||||
|
||||
def __init__(self, proto, data_spec):
|
||||
|
||||
self.proto = proto
|
||||
|
||||
assert 1 <= len(self) <= self.max_len, (
|
||||
f'{len(self)}: invalid {self.desc} length: not in range 1-{self.max_len}')
|
||||
|
||||
def __repr__(self):
|
||||
'return an initialization string'
|
||||
ret = str(self)
|
||||
|
|
@ -66,6 +74,6 @@ class OpReturnData(bytes, InitErrors):
|
|||
from ....color import blue, pink
|
||||
ret = str(self)
|
||||
if add_label:
|
||||
return blue('OP_RETURN data' + (' (hex): ' if self.display_hex else ': ')) + pink(ret)
|
||||
return blue(self.desc + (' (hex): ' if self.display_hex else ': ')) + pink(ret)
|
||||
else:
|
||||
return pink(ret)
|
||||
|
|
@ -32,8 +32,8 @@ class New(Base, TxNew):
|
|||
if hasattr(self, '_have_op_return_data'):
|
||||
die(1, 'Transaction may have at most one OP_RETURN data output!')
|
||||
self._have_op_return_data = True
|
||||
from .op_return_data import OpReturnData
|
||||
OpReturnData(self.proto, arg) # test data for validity
|
||||
from .data_output import DataOutput
|
||||
DataOutput(self.proto, arg) # test data for validity
|
||||
return arg
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class txdata_json_encoder(json.JSONEncoder):
|
|||
def default(self, o):
|
||||
if type(o).__name__.endswith('Amt'):
|
||||
return str(o)
|
||||
elif type(o).__name__ == 'OpReturnData':
|
||||
elif type(o).__name__.endswith('DataOutput'):
|
||||
return repr(o)
|
||||
else:
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
|
|
|||
|
|
@ -112,9 +112,9 @@ class unit_tests:
|
|||
ut.process_bad_data(bad_data)
|
||||
return True
|
||||
|
||||
def op_return_data(self, name, ut, desc='OpReturnData class'):
|
||||
def data_output(self, name, ut, desc='DataOutput class'):
|
||||
max_len = cfg._proto.max_op_return_data_len
|
||||
from mmgen.proto.btc.tx.op_return_data import OpReturnData
|
||||
from mmgen.proto.btc.tx.data_output import DataOutput
|
||||
vecs = [
|
||||
'data:=:ETH.ETH:0x86d526d6624AbC0178cF7296cD538Ecc080A95F1:0/1/0',
|
||||
'hexdata:3d3a4554482e4554483a30783836643532366436363234416243303137'
|
||||
|
|
@ -128,11 +128,11 @@ class unit_tests:
|
|||
'data:' + gr_uc[:24],
|
||||
]
|
||||
|
||||
assert OpReturnData(cfg._proto, vecs[0]) == OpReturnData(cfg._proto, vecs[1])
|
||||
assert DataOutput(cfg._proto, vecs[0]) == DataOutput(cfg._proto, vecs[1])
|
||||
|
||||
for vec in vecs:
|
||||
d = OpReturnData(cfg._proto, vec)
|
||||
assert d == OpReturnData(cfg._proto, repr(d)) # repr() must return a valid initializer
|
||||
d = DataOutput(cfg._proto, vec)
|
||||
assert d == DataOutput(cfg._proto, repr(d)) # repr() must return a valid initializer
|
||||
assert isinstance(d, bytes)
|
||||
assert isinstance(str(d), str)
|
||||
vmsg('-' * 80)
|
||||
|
|
@ -156,7 +156,7 @@ class unit_tests:
|
|||
]
|
||||
|
||||
def bad(n):
|
||||
return lambda: OpReturnData(cfg._proto, bad_data[n])
|
||||
return lambda: DataOutput(cfg._proto, bad_data[n])
|
||||
|
||||
vmsg('-' * 80)
|
||||
vmsg('Testing error handling:')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue