Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DefiTx: UpdateMasternode #82

Merged
merged 1 commit into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion defichain/transactions/builder/modules/masternode.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def resignmasternode(self, masternodeId: str, inputs=[]) -> Transaction:
"""
Creates a transaction resigning your masternode.

:param masternodeId: (required) masternodeId: txid of the creation of the masternode
:param masternodeId: (required) txid of the creation of the masternode
:type masternodeId: str
:param inputs: (optional) Inputs
:type inputs: TxInput
Expand All @@ -38,3 +38,23 @@ def resignmasternode(self, masternodeId: str, inputs=[]) -> Transaction:
defiTx = ResignMasternode(masternodeId)
return self._builder.build_defiTx(0, defiTx, inputs)

def updatemasternode(self, masternodeId: str, ownerAddress: str = None, operatorAddress: str = None,
rewardAddress: str = None, inputs=[]) -> Transaction:
"""
Creates a transaction to change owner, operator or reward address of a masternode.

:param masternodeId: (required) txid of the creation of the masternode
:type masternodeId: str
:param ownerAddress: (optional) new owner address
:type ownerAddress: str
:param operatorAddress: (optional) new operator address
:type operatorAddress: str
:param rewardAddress: (optional) new reward address
:type rewardAddress: str
:param inputs:(optional) Inputs
:type inputs: TxInput
:return: Transaction
"""
defiTx = UpdateMasternode(masternodeId, ownerAddress, operatorAddress, rewardAddress)
return self._builder.build_defiTx(0, defiTx, inputs)

2 changes: 2 additions & 0 deletions defichain/transactions/defitx/defitx.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ def deserialize(network: Any, hex: str) -> "BaseDefiTx":
return CreateMasternode.deserialize(network, hex[position:])
elif DefiTxType.OP_DEFI_TX_RESIGN_MASTER_NODE == defiTxType:
return ResignMasternode.deserialize(network, hex[position:])
elif DefiTxType.OP_DEFI_TX_UPDATE_MASTER_NODE == defiTxType:
return UpdateMasternode.deserialize(network, hex[position:])

# Pool
elif DefiTxType.OP_DEFI_TX_POOL_SWAP == defiTxType:
Expand Down
70 changes: 68 additions & 2 deletions defichain/transactions/defitx/modules/baseinput.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from defichain.transactions.utils import Token, Verify, BuildAddressAmounts
from defichain.transactions.address import Address
from defichain.transactions.utils import Converter, Calculate
from defichain.transactions.constants import AddressTypes


class BaseInput(ABC):
Expand Down Expand Up @@ -167,9 +168,11 @@ def deserialize_array(network: Any, hex: str) -> ["ScriptBalances"]:

for _ in range(numberOfReceivers):
length_addressTo = Converter.hex_to_int(hex[position: position + 2]) * 2
numberOfAmounts = Converter.hex_to_int(hex[position + 2 + length_addressTo: position + 2 + length_addressTo + 2])
numberOfAmounts = Converter.hex_to_int(
hex[position + 2 + length_addressTo: position + 2 + length_addressTo + 2])

scriptBalance = ScriptBalances.deserialize(network, hex[position: position + 2 + length_addressTo + 2 + numberOfAmounts * TokenBalanceInt32.estimated_size()])
scriptBalance = ScriptBalances.deserialize(network, hex[
position: position + 2 + length_addressTo + 2 + numberOfAmounts * TokenBalanceInt32.estimated_size()])
scriptBalances.append(scriptBalance)

position += 2 + length_addressTo + 2 + numberOfAmounts * TokenBalanceInt32.estimated_size()
Expand Down Expand Up @@ -214,3 +217,66 @@ def get_script(self) -> str:
def get_bytes_script(self) -> bytes:
return Converter.hex_to_bytes(self.get_script())


class MasternodeUpdates(BaseInput):
"""
Update Types: 1 byte, 1 = OwnerAddress, 2 = OperatorAddress, 3 = SetRewardAddress, 4 = RemRewardAddress
Address Types: 1 byte, 1 = p2pkh, 4 = p2wpkh, 0 to remove reward address
"""

@staticmethod
def deserialize(network: Any, hex: str):
pass

def __init__(self, updateType: int, address: str):
self._updateType, self._address, self._addressType = None, None, None
self.set_updateType(updateType)
self.set_address(address)

def __bytes__(self) -> bytes:
# Convert to Bytes
updateType = Converter.int_to_bytes(self.get_updateType(), 1)
addressType = Converter.int_to_bytes(self._addressType, 1)
if self.get_address() == "":
addressPubKeyHash = Converter.hex_to_bytes("")
else:
addressPubKeyHash = Converter.hex_to_bytes(Address.from_address(self.get_address()).get_publicKeyHash())

sizeAddressPubKeyHash = Converter.int_to_bytes(len(addressPubKeyHash), 1)

# Build UpdateMasternodeDefiTx
result = updateType
result += addressType
result += sizeAddressPubKeyHash
result += addressPubKeyHash

return result

# Get Information
def get_updateType(self) -> int:
return self._updateType

def get_address(self) -> str:
return self._address

def get_addressType(self) -> int:
return self._addressType

# Set Information
def set_updateType(self, updateType: int):
self._updateType = updateType

def set_address(self, address: str):
if address == "":
self._addressType = 0
self._address = address
else:
addressType = Address.from_address(address).get_addressType()
if addressType == AddressTypes.P2PKH:
self._addressType = 1
elif addressType == AddressTypes.P2WPKH:
self._addressType = 4
else:
raise AddressError("Only P2PKH and P2WPKH can be used to update the masternode")
self._address = address

156 changes: 138 additions & 18 deletions defichain/transactions/defitx/modules/masternode.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Any

from defichain.exceptions.transactions import DefiTxError
from defichain.exceptions.transactions import DefiTxError, AddressError
from defichain.transactions.constants import DefiTxType, AddressTypes
from defichain.transactions.address import Address, P2PKH, P2WPKH
from defichain.transactions.utils import Converter
from .baseinput import MasternodeUpdates
from .basedefitx import BaseDefiTx
from ..builddefitx import BuildDefiTx

Expand Down Expand Up @@ -149,21 +150,140 @@ def set_masternodeId(self, masternodeId) -> None:

class UpdateMasternode(BaseDefiTx):
"""
66ba4219032a90ca6a66370c553d27e1e7d5b17163a1d155464a82c3581b9f70

6a
4c54
44665478
6d #defi opcode
8e63dfce62b3695a68ccf9842c9416c9dcbaf5d4896b25cbf071b2bd994e0518 # masternodeId
02 # number of updates
02 # update type
01 # address type
14 # lenght of address
8e6137ff96462c8f4c3eeb664c098790b3d044df
03 # update type
04 # address type
14 # length of address
6bfc452b4cba7fcdf5fd311523a6706610e385e1
Builds the defi transaction: UpdateMasternode

:param masternodeId: (required) txid of the creation of the masternode
:type masternodeId: str
:param ownerAddress: (required) new owner address
:type ownerAddress: str
:param operatorAddress: (optional) new operator address
:type operatorAddress: str
:param rewardAddress: (optional) new reward address
:type rewardAddress: str
"""
pass

@staticmethod
def deserialize(network: Any, hex: str) -> "BaseDefiTx":
position = 0

masternodeId = bytes(reversed(Converter.hex_to_bytes(hex[position: position + 64]))).hex()
position += 64

numberOfUpdates = Converter.hex_to_int(hex[position: position + 2])
position += 2

ownerAddress: str = None
operatorAddress: str = None
rewardAddress: str = None

for _ in range(numberOfUpdates):
updateType = Converter.hex_to_int(hex[position: position + 2])
position += 2

addressType = Converter.hex_to_int(hex[position: position + 2])
position += 2

addressSize = Converter.hex_to_int(hex[position: position + 2]) * 2
position += 2

publicKeyHash = hex[position: position + addressSize]
position += addressSize

address = ""
if not updateType == 4:
if addressType == 1:
address = P2PKH.from_publicKeyHash(network, publicKeyHash).get_address()
elif addressType == 4:
address = P2WPKH.from_publicKeyHash(network, publicKeyHash).get_address()
else:
raise AddressError("Only P2PKH and P2WPKH can be deserialize")

if updateType == 1: # Owner Address
ownerAddress = address
elif updateType == 2: # Operator Address
operatorAddress = address
elif updateType == 3: # Set Reward Address
rewardAddress = address
elif updateType == 4: # Remove Reward Address
rewardAddress = address

return UpdateMasternode(masternodeId, ownerAddress, operatorAddress, rewardAddress)

def __init__(self, masternodeId: str, ownerAddress: str = None, operatorAddress: str = None,
rewardAddress: str = None):

self._masternodeId, self._ownerAddress, self._operatorAddress, self._rewardAddress = None, None, None, None
self.set_masternodeId(masternodeId)
self.set_ownerAddress(ownerAddress)
self.set_operatorAddress(operatorAddress)
self.set_rewardAddress(rewardAddress)

def __bytes__(self) -> bytes:
# Convert to Bytes
defiTxType = Converter.hex_to_bytes(self.get_defiTxType())
masternodeId = bytes(reversed(Converter.hex_to_bytes(self.get_masternodeId())))
updates = self.get_updates()
sizeUpdates = Converter.int_to_bytes(len(updates), 1)

# Build UpdateMasternodeDefiTx
result = defiTxType
result += masternodeId
result += sizeUpdates
for update in self.get_updates():
result += update.bytes()

return BuildDefiTx.build_defiTx(result)

def to_json(self) -> {}:
json = {}
json.update({"defiTxType": {"typeName": DefiTxType.from_hex(self.get_defiTxType()),
"typeHex": self.get_defiTxType()}})
json.update({"masternodeId": self.get_masternodeId()})
updates = []
for update in self.get_updates():
updates.append({"updateType": update.get_updateType(), "addressType": update.get_addressType(),
"address": update.get_address()})
json.update({"updates": updates})
return json

# Get Information
def get_defiTxType(self) -> str:
return DefiTxType.OP_DEFI_TX_UPDATE_MASTER_NODE

def get_masternodeId(self) -> str:
return self._masternodeId

def get_ownerAddress(self) -> str:
return self._ownerAddress

def get_operatorAddress(self) -> str:
return self._operatorAddress

def get_rewardAddress(self) -> str:
return self._rewardAddress

def get_updates(self) -> [MasternodeUpdates]:
updates = []
if self.get_ownerAddress():
updates.append(MasternodeUpdates(1, self.get_ownerAddress()))
if self.get_operatorAddress():
updates.append(MasternodeUpdates(2, self.get_operatorAddress()))
if self.get_rewardAddress():
if self.get_rewardAddress() == "remove":
updates.append(MasternodeUpdates(4, ""))
else:
updates.append(MasternodeUpdates(3, self.get_rewardAddress()))
return updates

# Set Information
def set_masternodeId(self, masternodeId) -> None:
self._masternodeId = masternodeId

def set_ownerAddress(self, ownerAddress) -> None:
self._ownerAddress = ownerAddress

def set_operatorAddress(self, operatorAddress) -> None:
self._operatorAddress = operatorAddress

def set_rewardAddress(self, rewardAddress) -> None:
self._rewardAddress = rewardAddress