Enhance dash spec tx support (#657)
This commit is contained in:
parent
2ab930e334
commit
88618f5f60
@ -29,6 +29,8 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from electrumx.lib.tx import Deserializer
|
from electrumx.lib.tx import Deserializer
|
||||||
|
from electrumx.lib.util import (pack_le_uint16, pack_le_int32, pack_le_uint32,
|
||||||
|
pack_le_int64, pack_varint, pack_varbytes)
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/dashpay/dips/blob/master/dip-0002.md
|
# https://github.com/dashpay/dips/blob/master/dip-0002.md
|
||||||
@ -36,6 +38,33 @@ class DashTx(namedtuple("DashTx",
|
|||||||
"version inputs outputs locktime "
|
"version inputs outputs locktime "
|
||||||
"tx_type extra_payload")):
|
"tx_type extra_payload")):
|
||||||
'''Class representing a Dash transaction'''
|
'''Class representing a Dash transaction'''
|
||||||
|
def serialize(self):
|
||||||
|
nLocktime = pack_le_uint32(self.locktime)
|
||||||
|
txins = (pack_varint(len(self.inputs)) +
|
||||||
|
b''.join(tx_in.serialize() for tx_in in self.inputs))
|
||||||
|
txouts = (pack_varint(len(self.outputs)) +
|
||||||
|
b''.join(tx_out.serialize() for tx_out in self.outputs))
|
||||||
|
|
||||||
|
if self.tx_type:
|
||||||
|
uVersion = pack_le_uint16(self.version)
|
||||||
|
uTxType = pack_le_uint16(self.tx_type)
|
||||||
|
vExtra = self._serialize_extra_payload()
|
||||||
|
return uVersion + uTxType + txins + txouts + nLocktime + vExtra
|
||||||
|
else:
|
||||||
|
nVersion = pack_le_int32(self.version)
|
||||||
|
return nVersion + txins + txouts + nLocktime
|
||||||
|
|
||||||
|
def _serialize_extra_payload(self):
|
||||||
|
extra = self.extra_payload
|
||||||
|
spec_tx_class = DeserializerDash.SPEC_TX_HANDLERS.get(self.tx_type)
|
||||||
|
if not spec_tx_class:
|
||||||
|
assert isinstance(extra, (bytes, bytearray))
|
||||||
|
return pack_varbytes(extra)
|
||||||
|
|
||||||
|
if not isinstance(extra, spec_tx_class):
|
||||||
|
raise ValueError('Dash tx_type does not conform with extra'
|
||||||
|
' payload class: %s, %s' % (self.tx_type, extra))
|
||||||
|
return pack_varbytes(extra.serialize())
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/dashpay/dips/blob/master/dip-0002-special-transactions.md
|
# https://github.com/dashpay/dips/blob/master/dip-0002-special-transactions.md
|
||||||
@ -45,61 +74,280 @@ class DashProRegTx(namedtuple("DashProRegTx",
|
|||||||
"KeyIdVoting operatorReward scriptPayout "
|
"KeyIdVoting operatorReward scriptPayout "
|
||||||
"inputsHash payloadSig")):
|
"inputsHash payloadSig")):
|
||||||
'''Class representing DIP3 ProRegTx'''
|
'''Class representing DIP3 ProRegTx'''
|
||||||
|
def serialize(self):
|
||||||
|
assert (len(self.ipAddress) == 16
|
||||||
|
and len(self.KeyIdOwner) == 20
|
||||||
|
and len(self.PubKeyOperator) == 48
|
||||||
|
and len(self.KeyIdVoting) == 20
|
||||||
|
and len(self.inputsHash) == 32)
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
pack_le_uint16(self.type) + # type
|
||||||
|
pack_le_uint16(self.mode) + # mode
|
||||||
|
self.collateralOutpoint.serialize() + # collateralOutpoint
|
||||||
|
self.ipAddress + # ipAddress
|
||||||
|
pack_le_uint16(self.port) + # port
|
||||||
|
self.KeyIdOwner + # KeyIdOwner
|
||||||
|
self.PubKeyOperator + # PubKeyOperator
|
||||||
|
self.KeyIdVoting + # KeyIdVoting
|
||||||
|
pack_le_uint16(self.operatorReward) + # operatorReward
|
||||||
|
pack_varbytes(self.scriptPayout) + # scriptPayout
|
||||||
|
self.inputsHash + # inputsHash
|
||||||
|
pack_varbytes(self.payloadSig) # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashProRegTx(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_le_uint16(), # type
|
||||||
|
deser._read_le_uint16(), # mode
|
||||||
|
deser._read_outpoint(), # collateralOutpoint
|
||||||
|
deser._read_nbytes(16), # ipAddress
|
||||||
|
deser._read_le_uint16(), # port
|
||||||
|
deser._read_nbytes(20), # KeyIdOwner
|
||||||
|
deser._read_nbytes(48), # PubKeyOperator
|
||||||
|
deser._read_nbytes(20), # KeyIdVoting
|
||||||
|
deser._read_le_uint16(), # operatorReward
|
||||||
|
deser._read_varbytes(), # scriptPayout
|
||||||
|
deser._read_nbytes(32), # inputsHash
|
||||||
|
deser._read_varbytes() # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashProUpServTx(namedtuple("DashProUpServTx",
|
class DashProUpServTx(namedtuple("DashProUpServTx",
|
||||||
"version proTXHash ipAddress port "
|
"version proTxHash ipAddress port "
|
||||||
"scriptOperatorPayout inputsHash "
|
"scriptOperatorPayout inputsHash "
|
||||||
"payloadSig")):
|
"payloadSig")):
|
||||||
'''Class representing DIP3 ProUpServTx'''
|
'''Class representing DIP3 ProUpServTx'''
|
||||||
|
def serialize(self):
|
||||||
|
assert (len(self.proTxHash) == 32
|
||||||
|
and len(self.ipAddress) == 16
|
||||||
|
and len(self.inputsHash) == 32
|
||||||
|
and len(self.payloadSig) == 96)
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
self.proTxHash + # proTxHash
|
||||||
|
self.ipAddress + # ipAddress
|
||||||
|
pack_le_uint16(self.port) + # port
|
||||||
|
pack_varbytes(self.scriptOperatorPayout) + # scriptOperatorPayout
|
||||||
|
self.inputsHash + # inputsHash
|
||||||
|
self.payloadSig # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashProUpServTx(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_nbytes(32), # proTxHash
|
||||||
|
deser._read_nbytes(16), # ipAddress
|
||||||
|
deser._read_le_uint16(), # port
|
||||||
|
deser._read_varbytes(), # scriptOperatorPayout
|
||||||
|
deser._read_nbytes(32), # inputsHash
|
||||||
|
deser._read_nbytes(96) # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashProUpRegTx(namedtuple("DashProUpRegTx",
|
class DashProUpRegTx(namedtuple("DashProUpRegTx",
|
||||||
"version proTXHash mode PubKeyOperator "
|
"version proTxHash mode PubKeyOperator "
|
||||||
"KeyIdVoting scriptPayout inputsHash "
|
"KeyIdVoting scriptPayout inputsHash "
|
||||||
"payloadSig")):
|
"payloadSig")):
|
||||||
'''Class representing DIP3 ProUpRegTx'''
|
'''Class representing DIP3 ProUpRegTx'''
|
||||||
|
def serialize(self):
|
||||||
|
assert (len(self.proTxHash) == 32
|
||||||
|
and len(self.PubKeyOperator) == 48
|
||||||
|
and len(self.KeyIdVoting) == 20
|
||||||
|
and len(self.inputsHash) == 32)
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
self.proTxHash + # proTxHash
|
||||||
|
pack_le_uint16(self.mode) + # mode
|
||||||
|
self.PubKeyOperator + # PubKeyOperator
|
||||||
|
self.KeyIdVoting + # KeyIdVoting
|
||||||
|
pack_varbytes(self.scriptPayout) + # scriptPayout
|
||||||
|
self.inputsHash + # inputsHash
|
||||||
|
pack_varbytes(self.payloadSig) # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashProUpRegTx(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_nbytes(32), # proTxHash
|
||||||
|
deser._read_le_uint16(), # mode
|
||||||
|
deser._read_nbytes(48), # PubKeyOperator
|
||||||
|
deser._read_nbytes(20), # KeyIdVoting
|
||||||
|
deser._read_varbytes(), # scriptPayout
|
||||||
|
deser._read_nbytes(32), # inputsHash
|
||||||
|
deser._read_varbytes() # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashProUpRevTx(namedtuple("DashProUpRevTx",
|
class DashProUpRevTx(namedtuple("DashProUpRevTx",
|
||||||
"version proTXHash reason "
|
"version proTxHash reason "
|
||||||
"inputsHash payloadSig")):
|
"inputsHash payloadSig")):
|
||||||
'''Class representing DIP3 ProUpRevTx'''
|
'''Class representing DIP3 ProUpRevTx'''
|
||||||
|
def serialize(self):
|
||||||
|
assert (len(self.proTxHash) == 32
|
||||||
|
and len(self.inputsHash) == 32
|
||||||
|
and len(self.payloadSig) == 96)
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
self.proTxHash + # proTxHash
|
||||||
|
pack_le_uint16(self.reason) + # reason
|
||||||
|
self.inputsHash + # inputsHash
|
||||||
|
self.payloadSig # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashProUpRevTx(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_nbytes(32), # proTxHash
|
||||||
|
deser._read_le_uint16(), # reason
|
||||||
|
deser._read_nbytes(32), # inputsHash
|
||||||
|
deser._read_nbytes(96) # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashCbTx(namedtuple("DashCbTx", "version height merkleRootMNList")):
|
class DashCbTx(namedtuple("DashCbTx", "version height merkleRootMNList")):
|
||||||
'''Class representing DIP4 coinbase special tx'''
|
'''Class representing DIP4 coinbase special tx'''
|
||||||
|
def serialize(self):
|
||||||
|
assert len(self.merkleRootMNList) == 32
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
pack_le_uint32(self.height) + # height
|
||||||
|
self.merkleRootMNList # merkleRootMNList
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashCbTx(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_le_uint32(), # height
|
||||||
|
deser._read_nbytes(32) # merkleRootMNList
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashSubTxRegister(namedtuple("DashSubTxRegister",
|
class DashSubTxRegister(namedtuple("DashSubTxRegister",
|
||||||
"version userName pubKey payloadSig")):
|
"version userName pubKey payloadSig")):
|
||||||
'''Class representing DIP5 SubTxRegister'''
|
'''Class representing DIP5 SubTxRegister'''
|
||||||
|
def serialize(self):
|
||||||
|
assert (len(self.pubKey) == 48
|
||||||
|
and len(self.payloadSig) == 96)
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
pack_varbytes(self.userName) + # userName
|
||||||
|
self.pubKey + # pubKey
|
||||||
|
self.payloadSig # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashSubTxRegister(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_varbytes(), # userName
|
||||||
|
deser._read_nbytes(48), # pubKey
|
||||||
|
deser._read_nbytes(96) # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashSubTxTopup(namedtuple("DashSubTxTopup",
|
class DashSubTxTopup(namedtuple("DashSubTxTopup",
|
||||||
"version regTxHash")):
|
"version regTxHash")):
|
||||||
'''Class representing DIP5 SubTxTopup'''
|
'''Class representing DIP5 SubTxTopup'''
|
||||||
|
def serialize(self):
|
||||||
|
assert len(self.regTxHash) == 32
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
self.regTxHash # regTxHash
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashSubTxTopup(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_nbytes(32) # regTxHash
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashSubTxResetKey(namedtuple("DashSubTxResetKey",
|
class DashSubTxResetKey(namedtuple("DashSubTxResetKey",
|
||||||
"version regTxHash hashPrevSubTx "
|
"version regTxHash hashPrevSubTx "
|
||||||
"creditFee newPubKey payloadSig")):
|
"creditFee newPubKey payloadSig")):
|
||||||
'''Class representing DIP5 SubTxResetKey'''
|
'''Class representing DIP5 SubTxResetKey'''
|
||||||
|
def serialize(self):
|
||||||
|
assert (len(self.regTxHash) == 32
|
||||||
|
and len(self.hashPrevSubTx) == 32
|
||||||
|
and len(self.newPubKey) == 48
|
||||||
|
and len(self.payloadSig) == 96)
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
self.regTxHash + # regTxHash
|
||||||
|
self.hashPrevSubTx + # hashPrevSubTx
|
||||||
|
pack_le_int64(self.creditFee) + # creditFee
|
||||||
|
self.newPubKey + # newPubKey
|
||||||
|
self.payloadSig # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashSubTxResetKey(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_nbytes(32), # regTxHash
|
||||||
|
deser._read_nbytes(32), # hashPrevSubTx
|
||||||
|
deser._read_le_int64(), # creditFee
|
||||||
|
deser._read_nbytes(48), # newPubKey
|
||||||
|
deser._read_nbytes(96) # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashSubTxCloseAccount(namedtuple("DashSubTxCloseAccount",
|
class DashSubTxCloseAccount(namedtuple("DashSubTxCloseAccount",
|
||||||
"version regTxHash hashPrevSubTx "
|
"version regTxHash hashPrevSubTx "
|
||||||
"creditFee payloadSig")):
|
"creditFee payloadSig")):
|
||||||
'''Class representing DIP5 SubTxCloseAccount'''
|
'''Class representing DIP5 SubTxCloseAccount'''
|
||||||
|
def serialize(self):
|
||||||
|
assert (len(self.regTxHash) == 32
|
||||||
|
and len(self.hashPrevSubTx) == 32
|
||||||
|
and len(self.payloadSig) == 96)
|
||||||
|
return (
|
||||||
|
pack_le_uint16(self.version) + # version
|
||||||
|
self.regTxHash + # regTxHash
|
||||||
|
self.hashPrevSubTx + # hashPrevSubTx
|
||||||
|
pack_le_int64(self.creditFee) + # creditFee
|
||||||
|
self.payloadSig # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_tx_extra(cls, deser):
|
||||||
|
return DashSubTxCloseAccount(
|
||||||
|
deser._read_le_uint16(), # version
|
||||||
|
deser._read_nbytes(32), # regTxHash
|
||||||
|
deser._read_nbytes(32), # hashPrevSubTx
|
||||||
|
deser._read_le_int64(), # creditFee
|
||||||
|
deser._read_nbytes(96) # payloadSig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# https://dash-docs.github.io/en/developer-reference#outpoint
|
# https://dash-docs.github.io/en/developer-reference#outpoint
|
||||||
class TxOutPoint(namedtuple("TxOutPoint", "hash index")):
|
class TxOutPoint(namedtuple("TxOutPoint", "hash index")):
|
||||||
'''Class representing tx output outpoint'''
|
'''Class representing tx output outpoint'''
|
||||||
|
def serialize(self):
|
||||||
|
assert len(self.hash) == 32
|
||||||
|
return (
|
||||||
|
self.hash + # hash
|
||||||
|
pack_le_uint32(self.index) # index
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_outpoint(cls, deser):
|
||||||
|
return TxOutPoint(
|
||||||
|
deser._read_nbytes(32), # hash
|
||||||
|
deser._read_le_uint32() # index
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeserializerDash(Deserializer):
|
class DeserializerDash(Deserializer):
|
||||||
'''Deserializer for Dash DIP2 special tx types'''
|
'''Deserializer for Dash DIP2 special tx types'''
|
||||||
|
# Supported Spec Tx types and corresponding classes mapping
|
||||||
PRO_REG_TX = 1
|
PRO_REG_TX = 1
|
||||||
PRO_UP_SERV_TX = 2
|
PRO_UP_SERV_TX = 2
|
||||||
PRO_UP_REG_TX = 3
|
PRO_UP_REG_TX = 3
|
||||||
@ -110,6 +358,21 @@ class DeserializerDash(Deserializer):
|
|||||||
SUB_TX_RESET_KEY = 10
|
SUB_TX_RESET_KEY = 10
|
||||||
SUB_TX_CLOSE_ACCOUNT = 11
|
SUB_TX_CLOSE_ACCOUNT = 11
|
||||||
|
|
||||||
|
SPEC_TX_HANDLERS = {
|
||||||
|
PRO_REG_TX: DashProRegTx,
|
||||||
|
PRO_UP_SERV_TX: DashProUpServTx,
|
||||||
|
PRO_UP_REG_TX: DashProUpRegTx,
|
||||||
|
PRO_UP_REV_TX: DashProUpRevTx,
|
||||||
|
CB_TX: DashCbTx,
|
||||||
|
SUB_TX_REGISTER: DashSubTxRegister,
|
||||||
|
SUB_TX_TOPUP: DashSubTxTopup,
|
||||||
|
SUB_TX_RESET_KEY: DashSubTxResetKey,
|
||||||
|
SUB_TX_CLOSE_ACCOUNT: DashSubTxCloseAccount,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _read_outpoint(self):
|
||||||
|
return TxOutPoint.read_outpoint(self)
|
||||||
|
|
||||||
def read_tx(self):
|
def read_tx(self):
|
||||||
header = self._read_le_uint32()
|
header = self._read_le_uint32()
|
||||||
tx_type = header >> 16 # DIP2 tx type
|
tx_type = header >> 16 # DIP2 tx type
|
||||||
@ -128,24 +391,11 @@ class DeserializerDash(Deserializer):
|
|||||||
if tx_type:
|
if tx_type:
|
||||||
extra_payload_size = self._read_varint()
|
extra_payload_size = self._read_varint()
|
||||||
end = self.cursor + extra_payload_size
|
end = self.cursor + extra_payload_size
|
||||||
if tx_type == DeserializerDash.CB_TX:
|
spec_tx_class = DeserializerDash.SPEC_TX_HANDLERS.get(tx_type)
|
||||||
extra_payload = self._read_cb_tx()
|
if spec_tx_class:
|
||||||
elif tx_type == DeserializerDash.PRO_REG_TX:
|
read_method = getattr(spec_tx_class, 'read_tx_extra', None)
|
||||||
extra_payload = self._read_pro_reg_tx()
|
extra_payload = read_method(self)
|
||||||
elif tx_type == DeserializerDash.PRO_UP_SERV_TX:
|
assert isinstance(extra_payload, spec_tx_class)
|
||||||
extra_payload = self._read_pro_up_serv_tx()
|
|
||||||
elif tx_type == DeserializerDash.PRO_UP_REG_TX:
|
|
||||||
extra_payload = self._read_pro_up_reg_tx()
|
|
||||||
elif tx_type == DeserializerDash.PRO_UP_REV_TX:
|
|
||||||
extra_payload = self._read_pro_up_rev_tx()
|
|
||||||
elif tx_type == DeserializerDash.SUB_TX_REGISTER:
|
|
||||||
extra_payload = self._read_sub_tx_register()
|
|
||||||
elif tx_type == DeserializerDash.SUB_TX_TOPUP:
|
|
||||||
extra_payload = self._read_sub_tx_topup()
|
|
||||||
elif tx_type == DeserializerDash.SUB_TX_RESET_KEY:
|
|
||||||
extra_payload = self._read_sub_tx_reset_key()
|
|
||||||
elif tx_type == DeserializerDash.SUB_TX_CLOSE_ACCOUNT:
|
|
||||||
extra_payload = self._read_sub_tx_close_account()
|
|
||||||
else:
|
else:
|
||||||
extra_payload = self._read_nbytes(extra_payload_size)
|
extra_payload = self._read_nbytes(extra_payload_size)
|
||||||
assert self.cursor == end
|
assert self.cursor == end
|
||||||
@ -153,98 +403,3 @@ class DeserializerDash(Deserializer):
|
|||||||
extra_payload = b''
|
extra_payload = b''
|
||||||
tx = DashTx(version, inputs, outputs, locktime, tx_type, extra_payload)
|
tx = DashTx(version, inputs, outputs, locktime, tx_type, extra_payload)
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
def _read_outpoint(self):
|
|
||||||
return TxOutPoint(
|
|
||||||
self._read_nbytes(32), # hash
|
|
||||||
self._read_le_uint32() # index
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_pro_reg_tx(self):
|
|
||||||
return DashProRegTx(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_le_uint16(), # type
|
|
||||||
self._read_le_uint16(), # mode
|
|
||||||
self._read_outpoint(), # collateralOutpoint
|
|
||||||
self._read_nbytes(16), # ipAddress
|
|
||||||
self._read_le_uint16(), # port
|
|
||||||
self._read_nbytes(20), # KeyIdOwner
|
|
||||||
self._read_nbytes(48), # PubKeyOperator
|
|
||||||
self._read_nbytes(20), # KeyIdVoting
|
|
||||||
self._read_le_uint16(), # operatorReward
|
|
||||||
self._read_varbytes(), # scriptPayout
|
|
||||||
self._read_nbytes(32), # inputsHash
|
|
||||||
self._read_varbytes() # payloadSig
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_pro_up_serv_tx(self):
|
|
||||||
return DashProUpServTx(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_nbytes(32), # proTXHash
|
|
||||||
self._read_nbytes(16), # ipAddress
|
|
||||||
self._read_le_uint16(), # port
|
|
||||||
self._read_varbytes(), # scriptOperatorPayout
|
|
||||||
self._read_nbytes(32), # inputsHash
|
|
||||||
self._read_nbytes(96) # payloadSig BLSSig
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_pro_up_reg_tx(self):
|
|
||||||
return DashProUpRegTx(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_nbytes(32), # proTXHash
|
|
||||||
self._read_le_uint16(), # mode
|
|
||||||
self._read_nbytes(48), # PubKeyOperator
|
|
||||||
self._read_nbytes(20), # KeyIdOwner
|
|
||||||
self._read_varbytes(), # scriptPayout
|
|
||||||
self._read_nbytes(32), # inputsHash
|
|
||||||
self._read_varbytes() # payloadSig
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_pro_up_rev_tx(self):
|
|
||||||
return DashProUpRevTx(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_nbytes(32), # proTXHash
|
|
||||||
self._read_le_uint16(), # reason
|
|
||||||
self._read_nbytes(32), # inputsHash
|
|
||||||
self._read_nbytes(96) # payloadSig BLSSig
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_cb_tx(self):
|
|
||||||
return DashCbTx(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_le_uint32(), # height
|
|
||||||
self._read_nbytes(32) # merkleRootMNList as bytes
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_sub_tx_register(self):
|
|
||||||
return DashSubTxRegister(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_varbytes(), # userName
|
|
||||||
self._read_nbytes(48), # pubKey BLSPubKey
|
|
||||||
self._read_nbytes(96) # payloadSig BLSSig
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_sub_tx_topup(self):
|
|
||||||
return DashSubTxTopup(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_nbytes(32) # regTxHash
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_sub_tx_reset_key(self):
|
|
||||||
return DashSubTxResetKey(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_nbytes(32), # regTxHash
|
|
||||||
self._read_nbytes(32), # hashPrevSubTx
|
|
||||||
self._read_le_int64(), # creditFee
|
|
||||||
self._read_nbytes(48), # newPubKey BLSPubKey
|
|
||||||
self._read_nbytes(96) # payloadSig BLSSig
|
|
||||||
)
|
|
||||||
|
|
||||||
def _read_sub_tx_close_account(self):
|
|
||||||
return DashSubTxCloseAccount(
|
|
||||||
self._read_le_uint16(), # version
|
|
||||||
self._read_nbytes(32), # regTxHash
|
|
||||||
self._read_nbytes(32), # hashPrevSubTx
|
|
||||||
self._read_le_int64(), # creditFee
|
|
||||||
self._read_nbytes(96) # payloadSig BLSSig
|
|
||||||
)
|
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
import electrumx.lib.tx_dash as lib_tx_dash
|
import electrumx.lib.tx_dash as lib_tx_dash
|
||||||
|
|
||||||
|
|
||||||
|
bfh = bytes.fromhex
|
||||||
|
|
||||||
|
|
||||||
V2_TX = (
|
V2_TX = (
|
||||||
'020000000192809f0b234cb850d71d020e678e93f074648ed0df5affd0c46d3bcb177f'
|
'020000000192809f0b234cb850d71d020e678e93f074648ed0df5affd0c46d3bcb177f'
|
||||||
'9ccf020000008b483045022100c5403bcf86c3ae7b8fd4ca0d1e4df6729cc1af05ff95'
|
'9ccf020000008b483045022100c5403bcf86c3ae7b8fd4ca0d1e4df6729cc1af05ff95'
|
||||||
@ -125,11 +130,11 @@ SUB_TX_RESET_KEY = (
|
|||||||
'3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217'
|
'3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217'
|
||||||
'4d22769c3a4f90b2dcd0de88ac00000000da0100d384e42374e8abfeffffff01570b00'
|
'4d22769c3a4f90b2dcd0de88ac00000000da0100d384e42374e8abfeffffff01570b00'
|
||||||
'0000a40100b67ffbbd095de31ea3844675af3e98e9601210293360bf2a2e810673412b'
|
'0000a40100b67ffbbd095de31ea3844675af3e98e9601210293360bf2a2e810673412b'
|
||||||
'c6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e81067341'
|
'c6e8e0e358f3fb7bdbe9a667b3d0e803000000000000601210293360bf2a2e81067341'
|
||||||
'2bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e810673'
|
'2bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e810673'
|
||||||
'412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e8106'
|
'412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e8106'
|
||||||
'73412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e81'
|
'73412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360bf2a2e81'
|
||||||
'0673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761cabcdefabcdef')
|
'0673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761cabcdefab')
|
||||||
|
|
||||||
|
|
||||||
SUB_TX_CLOSE_ACCOUNT = (
|
SUB_TX_CLOSE_ACCOUNT = (
|
||||||
@ -140,10 +145,10 @@ SUB_TX_CLOSE_ACCOUNT = (
|
|||||||
'3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217'
|
'3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217'
|
||||||
'4d22769c3a4f90b2dcd0de88ac00000000aa0100d384e42374e8abfeffffff01570b00'
|
'4d22769c3a4f90b2dcd0de88ac00000000aa0100d384e42374e8abfeffffff01570b00'
|
||||||
'0000a40100b67ffbbd095de31ea3844675af3e98e9601210293360bf2a2e810673412b'
|
'0000a40100b67ffbbd095de31ea3844675af3e98e9601210293360bf2a2e810673412b'
|
||||||
'c6e8e0e358f3fb7bdbe9a12bc6e8e0e358f3fb7bdbe9a62bc6e8e0e358f3fb7bdbe9a6'
|
'c6e8e0e358f3fb7bdbe9a12bc6e8e803000000000000a62bc6e8e0e358f3fb7bdbe9a6'
|
||||||
'67b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9'
|
'67b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9'
|
||||||
'a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdb'
|
'a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdb'
|
||||||
'e9a667b3d0103f761cabcdefabcdef')
|
'e9a667b3d0103f761cabcdefab')
|
||||||
|
|
||||||
|
|
||||||
UNKNOWN_SPEC_TX = (
|
UNKNOWN_SPEC_TX = (
|
||||||
@ -157,7 +162,7 @@ UNKNOWN_SPEC_TX = (
|
|||||||
'c6e8e0e358f3fb7bdbe9a12bc6e8e0e358f3fb7bdbe9a62bc6e8e0e358f3fb7bdbe9a6'
|
'c6e8e0e358f3fb7bdbe9a12bc6e8e0e358f3fb7bdbe9a62bc6e8e0e358f3fb7bdbe9a6'
|
||||||
'67b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9'
|
'67b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9'
|
||||||
'a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdb'
|
'a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdb'
|
||||||
'e9a667b3d0103f761cabcdefabcdef')
|
'e9a667b3d0103f761cabcdefab')
|
||||||
|
|
||||||
|
|
||||||
WRONG_SPEC_TX = ( # Tx version < 3
|
WRONG_SPEC_TX = ( # Tx version < 3
|
||||||
@ -166,77 +171,294 @@ WRONG_SPEC_TX = ( # Tx version < 3
|
|||||||
'1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231'
|
'1171e06d7c372db92c65022061c1ec3c92f2e76bb7fb1b548d854f19a41e6421267231'
|
||||||
'74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b'
|
'74150412caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b'
|
||||||
'3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217'
|
'3d0103f761cc69a211feffffff0189fa433e000000001976a914551ab8ca96a9142217'
|
||||||
'4d22769c3a4f90b2dcd0de88ac00000000aa0100d384e42374e8abfeffffff01570b00'
|
'4d22769c3a4f90b2dcd0de88ac00000000')
|
||||||
'0000')
|
|
||||||
|
|
||||||
|
|
||||||
def test_dash_v2_tx():
|
def test_dash_v2_tx():
|
||||||
test = bytes.fromhex(V2_TX)
|
test = bfh(V2_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 2
|
||||||
|
assert tx.tx_type == 0
|
||||||
|
assert tx.extra_payload == b''
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_cb_tx():
|
def test_dash_tx_cb_tx():
|
||||||
test = bytes.fromhex(CB_TX)
|
test = bfh(CB_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 5
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert extra.height == 264132
|
||||||
|
assert len(extra.merkleRootMNList) == 32
|
||||||
|
assert extra.merkleRootMNList == bfh(
|
||||||
|
'76629a6e42fb519188f65889fd3ac0201be87aa227462b5643e8bb2ec1d7a82a')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_pro_reg_tx():
|
def test_dash_tx_pro_reg_tx():
|
||||||
test = bytes.fromhex(PRO_REG_TX)
|
test = bfh(PRO_REG_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 1
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert extra.type == 0
|
||||||
|
assert extra.mode == 0
|
||||||
|
assert len(extra.collateralOutpoint.hash) == 32
|
||||||
|
assert extra.collateralOutpoint.hash == bfh(
|
||||||
|
'4de1afa0a321bc88c34978d4eeba739256b86f8d8cdf47651b6f60e451f0a3de')
|
||||||
|
assert extra.collateralOutpoint.index == 1
|
||||||
|
assert len(extra.ipAddress) == 16
|
||||||
|
assert extra.ipAddress == bfh('00000000000000000000ffff12ca34aa')
|
||||||
|
assert extra.port == 12149
|
||||||
|
assert len(extra.KeyIdOwner) == 20
|
||||||
|
assert extra.KeyIdOwner == bfh(
|
||||||
|
'2b3edeed6842db1f59cf35de1ab5721094f049d0')
|
||||||
|
assert len(extra.PubKeyOperator) == 48
|
||||||
|
assert extra.PubKeyOperator == bfh(
|
||||||
|
'00ab986c589053b3f3bd720724e75e18581afdca54bce80d14750b1bcf920215'
|
||||||
|
'8fe6c596ce8391815265747bd4a2009e')
|
||||||
|
assert len(extra.KeyIdVoting) == 20
|
||||||
|
assert extra.KeyIdVoting == bfh(
|
||||||
|
'2b3edeed6842db1f59cf35de1ab5721094f049d0')
|
||||||
|
assert extra.operatorReward == 0
|
||||||
|
assert extra.scriptPayout == bfh(
|
||||||
|
'76a9149bf5948b901a1e3e54e42c6e10496a17cd4067e088ac')
|
||||||
|
assert len(extra.inputsHash) == 32
|
||||||
|
assert extra.inputsHash == bfh(
|
||||||
|
'54d046585434668b4ee664c597864248b8a6aac33a7b2f4fcd1cc1b5da474a8a')
|
||||||
|
assert extra.payloadSig == bfh(
|
||||||
|
'1fc1617ae83406c92a9132f14f9fff1487f2890f401e776fdddd639bc505'
|
||||||
|
'5c456268cf7497400d3196109c8cd31b94732caf6937d63de81d9a5be4db'
|
||||||
|
'5beb83f9aa')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_pro_up_serv_tx():
|
def test_dash_tx_pro_up_serv_tx():
|
||||||
test = bytes.fromhex(PRO_UP_SERV_TX)
|
test = bfh(PRO_UP_SERV_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 2
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert len(extra.proTxHash) == 32
|
||||||
|
assert extra.proTxHash == bfh(
|
||||||
|
'3c6dca244f49f19d3f09889753ffff1fec5bb8f9f5bd5bc09dabd999da21198f')
|
||||||
|
assert len(extra.ipAddress) == 16
|
||||||
|
assert extra.ipAddress == bfh('00000000000000000000ffff5fb73580')
|
||||||
|
assert extra.port == 4391
|
||||||
|
assert extra.scriptOperatorPayout == bfh(
|
||||||
|
'76a91421851058431a7d722e8e8dd9509e7f2b8e7042ec88ac')
|
||||||
|
assert len(extra.inputsHash) == 32
|
||||||
|
assert extra.inputsHash == bfh(
|
||||||
|
'efcfe3d578914bb48c6bd71b3459d384e4237446d521c9e2c6'
|
||||||
|
'b6fcf019b5aafc')
|
||||||
|
assert len(extra.payloadSig) == 96
|
||||||
|
assert extra.payloadSig == bfh(
|
||||||
|
'99443fe14f644cfa47086e8897cf7b546a67723d4a8ec5353a82f962a96e'
|
||||||
|
'c3cea328343b647aace2897d6eddd0b8c8ee0f2e56f6733aed2e9f0006ca'
|
||||||
|
'afa6fc21c18a013c619d6e37af8d2f0985e3b769abc38ffa60e46c365a38'
|
||||||
|
'd9fa0d44fd62')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_pro_up_reg_tx():
|
def test_dash_tx_pro_up_reg_tx():
|
||||||
test = bytes.fromhex(PRO_UP_REG_TX)
|
test = bfh(PRO_UP_REG_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 3
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert len(extra.proTxHash) == 32
|
||||||
|
assert extra.proTxHash == bfh(
|
||||||
|
'aeb817f94b8e699b58130a53d2fbe98d5519c2abe3b15e6f36c9abeb32e4dcce')
|
||||||
|
assert extra.mode == 0
|
||||||
|
assert len(extra.PubKeyOperator) == 48
|
||||||
|
assert extra.PubKeyOperator == bfh(
|
||||||
|
'1061eb559a64427ad239830742ef59591cdbbdffda7d3f5e7a2d95b9607a'
|
||||||
|
'd80e389191e44c59ea5987b85e6d0e3eb527')
|
||||||
|
assert len(extra.KeyIdVoting) == 20
|
||||||
|
assert extra.KeyIdVoting == bfh(
|
||||||
|
'b9e198fa7a745913c9278ec993d4472a95dac425')
|
||||||
|
assert extra.scriptPayout == bfh(
|
||||||
|
'76a914eebbacffff3a55437803e0efb68a7d591e0409d188ac')
|
||||||
|
assert len(extra.inputsHash) == 32
|
||||||
|
assert extra.inputsHash == bfh(
|
||||||
|
'0eb0067e6ccdd2acb96e7279113702218f3f0ab6f2287e14c11c5be6f2051d5a')
|
||||||
|
assert extra.payloadSig == bfh(
|
||||||
|
'20cb00124d838b02207097048cb668244cd79df825eb2d4d211fd2c4604c1'
|
||||||
|
'8b30e1ae9bb654787144d16856676efff180889f05b5c9121a483b4ae3f0e'
|
||||||
|
'a0ff3faf')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_pro_up_rev_tx():
|
def test_dash_tx_pro_up_rev_tx():
|
||||||
test = bytes.fromhex(PRO_UP_REV_TX)
|
test = bfh(PRO_UP_REV_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 4
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert len(extra.proTxHash) == 32
|
||||||
|
assert extra.proTxHash == bfh(
|
||||||
|
'b67ffbbd095de31ea38446754b6bf251287936d2881d58b7c4efae0b54c75e9f')
|
||||||
|
assert extra.reason == 0
|
||||||
|
assert len(extra.inputsHash) == 32
|
||||||
|
assert extra.inputsHash == bfh(
|
||||||
|
'eb073521b60306717f1d4feb3e9022f886b97bf981137684716a7d3d7e45b7fe')
|
||||||
|
assert len(extra.payloadSig) == 96
|
||||||
|
assert extra.payloadSig == bfh(
|
||||||
|
'83f4bb5530f7c5954e8b1ad50a74a9e1d65dcdcbe4acb8cbe3671abc7911'
|
||||||
|
'e8c3954856c4da7e5fd242f2e4f5546f08d90849245bc593d1605654e1a9'
|
||||||
|
'9cd0a79e9729799742c48d4920044666ad25a85fd093559c43e4900e634c'
|
||||||
|
'371b9b8d89ba')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_sub_tx_register_tx():
|
def test_dash_tx_sub_tx_register_tx():
|
||||||
test = bytes.fromhex(SUB_TX_REGISTER)
|
test = bfh(SUB_TX_REGISTER)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 8
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert extra.userName == b'abc'
|
||||||
|
assert len(extra.pubKey) == 48
|
||||||
|
assert extra.pubKey == bfh(
|
||||||
|
'8e7042ec88acefcfe3d578914bb48c6bd71b3459d384e42374e8abfeffff'
|
||||||
|
'ff01570b0000000000001976a91490c5ce9d')
|
||||||
|
assert len(extra.payloadSig) == 96
|
||||||
|
assert extra.payloadSig == bfh(
|
||||||
|
'8bc992a88ac00000000a40100b67ffbbd095de31ea38446754e8abfeffff'
|
||||||
|
'ff01570b0000000000001976a91490c5ce9d8bc992a88ac00000000a4010'
|
||||||
|
'0b67ffbbd095de31ea38446754e8abfeffffff01570b0000000000001976'
|
||||||
|
'a91490c5ce9d')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_sub_tx_topup_tx():
|
def test_dash_tx_sub_tx_topup_tx():
|
||||||
test = bytes.fromhex(SUB_TX_TOPUP)
|
test = bfh(SUB_TX_TOPUP)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 9
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert len(extra.regTxHash) == 32
|
||||||
|
assert extra.regTxHash == bfh(
|
||||||
|
'd384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31ea3844675')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_sub_tx_reset_key_tx():
|
def test_dash_tx_sub_tx_reset_key_tx():
|
||||||
test = bytes.fromhex(SUB_TX_RESET_KEY)
|
test = bfh(SUB_TX_RESET_KEY)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 10
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert len(extra.regTxHash) == 32
|
||||||
|
assert extra.regTxHash == bfh(
|
||||||
|
'd384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31ea3844675')
|
||||||
|
assert len(extra.hashPrevSubTx) == 32
|
||||||
|
assert extra.hashPrevSubTx == bfh(
|
||||||
|
'af3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0')
|
||||||
|
assert extra.creditFee == 1000
|
||||||
|
assert len(extra.newPubKey) == 48
|
||||||
|
assert extra.newPubKey == bfh(
|
||||||
|
'601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f7'
|
||||||
|
'61caf3e98e9601210293360bf2a2e810673')
|
||||||
|
assert len(extra.payloadSig) == 96
|
||||||
|
assert extra.payloadSig == bfh(
|
||||||
|
'412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360b'
|
||||||
|
'f2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e960'
|
||||||
|
'1210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761'
|
||||||
|
'cabcdefab')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_sub_tx_close_account_tx():
|
def test_dash_tx_sub_tx_close_account_tx():
|
||||||
test = bytes.fromhex(SUB_TX_CLOSE_ACCOUNT)
|
test = bfh(SUB_TX_CLOSE_ACCOUNT)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 11
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra.version == 1
|
||||||
|
assert len(extra.regTxHash) == 32
|
||||||
|
assert extra.regTxHash == bfh(
|
||||||
|
'd384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31ea3844675')
|
||||||
|
assert len(extra.hashPrevSubTx) == 32
|
||||||
|
assert extra.hashPrevSubTx == bfh(
|
||||||
|
'af3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a12bc6e8')
|
||||||
|
assert extra.creditFee == 1000
|
||||||
|
assert len(extra.payloadSig) == 96
|
||||||
|
assert extra.payloadSig == bfh(
|
||||||
|
'a62bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e9601210293360b'
|
||||||
|
'f2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761caf3e98e960'
|
||||||
|
'1210293360bf2a2e810673412bc6e8e0e358f3fb7bdbe9a667b3d0103f761'
|
||||||
|
'cabcdefab')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_unknown_spec_tx():
|
def test_dash_tx_unknown_spec_tx():
|
||||||
test = bytes.fromhex(UNKNOWN_SPEC_TX)
|
test = bfh(UNKNOWN_SPEC_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 3
|
||||||
|
assert tx.tx_type == 187
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra == bfh(
|
||||||
|
'0100d384e42374e8abfeffffff01570b000000a40100b67ffbbd095de31e'
|
||||||
|
'a3844675af3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7b'
|
||||||
|
'dbe9a12bc6e8e0e358f3fb7bdbe9a62bc6e8e0e358f3fb7bdbe9a667b3d0'
|
||||||
|
'103f761caf3e98e9601210293360bf2a2e810673412bc6e8e0e358f3fb7b'
|
||||||
|
'dbe9a667b3d0103f761caf3e98e9601210293360bf2a2e810673412bc6e8'
|
||||||
|
'e0e358f3fb7bdbe9a667b3d0103f761cabcdefab')
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
def test_dash_tx_wrong_spec_tx():
|
def test_dash_tx_wrong_spec_tx():
|
||||||
test = bytes.fromhex(WRONG_SPEC_TX)
|
test = bfh(WRONG_SPEC_TX)
|
||||||
deser = lib_tx_dash.DeserializerDash(test)
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
tx = deser.read_tx()
|
tx = deser.read_tx()
|
||||||
|
assert tx.version == 12255234
|
||||||
|
assert tx.tx_type == 0
|
||||||
|
extra = tx.extra_payload
|
||||||
|
assert extra == b''
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ser == test
|
||||||
|
|
||||||
|
|
||||||
|
def test_dash_tx_serialize_wrong_tx_type():
|
||||||
|
test = bfh(CB_TX)
|
||||||
|
deser = lib_tx_dash.DeserializerDash(test)
|
||||||
|
tx = deser.read_tx()
|
||||||
|
assert tx.tx_type == 5
|
||||||
|
tx = tx._replace(tx_type=4)
|
||||||
|
assert tx.tx_type == 4
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
ser = tx.serialize()
|
||||||
|
assert ('Dash tx_type does not conform'
|
||||||
|
' with extra payload class' in str(excinfo.value))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user