Skip to content

Commit

Permalink
Merge branch 'main' into main-into-next-2024-10-23
Browse files Browse the repository at this point in the history
  • Loading branch information
andreibancioiu committed Oct 23, 2024
2 parents 7bd5ddc + faf9d90 commit ce6f2e0
Show file tree
Hide file tree
Showing 20 changed files with 149 additions and 227 deletions.
2 changes: 2 additions & 0 deletions multiversx_sdk/abi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from multiversx_sdk.abi.biguint_value import BigUIntValue
from multiversx_sdk.abi.bool_value import BoolValue
from multiversx_sdk.abi.bytes_value import BytesValue
from multiversx_sdk.abi.code_metadata_value import CodeMetadataValue
from multiversx_sdk.abi.enum_value import EnumValue
from multiversx_sdk.abi.fields import Field
from multiversx_sdk.abi.list_value import ListValue
Expand All @@ -32,6 +33,7 @@
"BigUIntValue",
"BoolValue",
"BytesValue",
"CodeMetadataValue",
"EnumValue",
"Field",
"ListValue",
Expand Down
3 changes: 2 additions & 1 deletion multiversx_sdk/abi/abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from multiversx_sdk.abi.biguint_value import BigUIntValue
from multiversx_sdk.abi.bool_value import BoolValue
from multiversx_sdk.abi.bytes_value import BytesValue
from multiversx_sdk.abi.code_metadata_value import CodeMetadataValue
from multiversx_sdk.abi.counted_variadic_values import CountedVariadicValues
from multiversx_sdk.abi.enum_value import EnumValue
from multiversx_sdk.abi.fields import Field
Expand Down Expand Up @@ -284,7 +285,7 @@ def _create_prototype(self, type_formula: TypeFormula) -> Any:
if name == "EgldOrEsdtTokenIdentifier":
return TokenIdentifierValue()
if name == "CodeMetadata":
return BytesValue()
return CodeMetadataValue()
if name == "tuple":
return TupleValue([self._create_prototype(type_parameter) for type_parameter in type_formula.type_parameters])
if name == "Option":
Expand Down
46 changes: 46 additions & 0 deletions multiversx_sdk/abi/code_metadata_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import io
from typing import Any

from multiversx_sdk.abi.shared import read_bytes_exactly
from multiversx_sdk.core.code_metadata import (CODE_METADATA_LENGTH,
CodeMetadata)


class CodeMetadataValue:
def __init__(self, value: bytes = b"") -> None:
self.value = value

@classmethod
def new_from_code_metadata(cls, code_metadata: CodeMetadata) -> "CodeMetadataValue":
return cls(code_metadata.serialize())

def encode_nested(self, writer: io.BytesIO):
writer.write(self.value)

def encode_top_level(self, writer: io.BytesIO):
writer.write(self.value)

def decode_nested(self, reader: io.BytesIO):
length = CODE_METADATA_LENGTH
data = read_bytes_exactly(reader, length)
self.value = data

def decode_top_level(self, data: bytes):
self.value = data

def set_payload(self, value: Any):
if isinstance(value, bytes):
self.value = CodeMetadata.new_from_bytes(value).serialize()
elif isinstance(value, CodeMetadata):
self.value = value.serialize()
else:
raise ValueError(f"cannot set payload for code metadata (should be either a CodeMetadata or bytes, but got: {type(value)})")

def get_payload(self) -> Any:
return self.value

def __eq__(self, other: Any) -> bool:
return isinstance(other, CodeMetadataValue) and self.value == other.value

def __bytes__(self) -> bytes:
return self.value
33 changes: 33 additions & 0 deletions multiversx_sdk/abi/code_metadata_value_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import re

import pytest

from multiversx_sdk.abi.code_metadata_value import CodeMetadataValue
from multiversx_sdk.core.code_metadata import CodeMetadata


def test_new_from_code_metadata():
value = CodeMetadataValue.new_from_code_metadata(CodeMetadata())
assert value.get_payload() == bytes([0x05, 0x00])

value = CodeMetadataValue.new_from_code_metadata(CodeMetadata(upgradeable=True, readable=True, payable=True, payable_by_contract=True))
assert value.get_payload() == bytes([0x05, 0x06])


def test_set_payload_and_get_payload():
# Simple
value = CodeMetadataValue()
value.set_payload(bytes([0x05, 0x00]))
assert value.get_payload() == bytes([0x05, 0x00])

# With CodeMetadata
value = CodeMetadataValue()
value.set_payload(CodeMetadata(upgradeable=True, readable=True, payable=True, payable_by_contract=True))
assert value.get_payload() == bytes([0x05, 0x06])

# With errors
with pytest.raises(ValueError, match=re.escape("cannot set payload for code metadata (should be either a CodeMetadata or bytes, but got: <class 'dict'>)")):
CodeMetadataValue().set_payload({})

with pytest.raises(ValueError, match="code metadata buffer has length 4, expected 2"):
CodeMetadataValue().set_payload(bytes([0, 1, 2, 3]))
6 changes: 1 addition & 5 deletions multiversx_sdk/converters/transactions_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def transaction_to_dictionary(self, transaction: ITransaction) -> Dict[str, Any]
"options": transaction.options,
"guardian": transaction.guardian,
"signature": self._value_to_hex_or_empty(transaction.signature),
"guardianSignature": self._value_to_hex_or_empty(transaction.guardian_signature),
"relayer": transaction.relayer,
"innerTransactions": [self.transaction_to_dictionary(inner_tx) for inner_tx in transaction.inner_transactions]
"guardianSignature": self._value_to_hex_or_empty(transaction.guardian_signature)
}

def dictionary_to_transaction(self, dictionary: Dict[str, Any]) -> Transaction:
Expand All @@ -50,8 +48,6 @@ def dictionary_to_transaction(self, dictionary: Dict[str, Any]) -> Transaction:
options=dictionary.get("options", None),
signature=self._bytes_from_hex(dictionary.get("signature", "")),
guardian_signature=self._bytes_from_hex(dictionary.get("guardianSignature", "")),
relayer=dictionary.get("relayer", None),
inner_transactions=[self.dictionary_to_transaction(inner_tx) for inner_tx in dictionary.get("innerTransactions", [])],
)

def _ensure_mandatory_fields_for_transaction(self, dictionary: Dict[str, Any]) -> None:
Expand Down
31 changes: 0 additions & 31 deletions multiversx_sdk/converters/transactions_converter_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,3 @@ def test_transaction_converter():
restored_tx = converter.dictionary_to_transaction(tx_as_dict)

assert transaction == restored_tx


def test_transaction_from_dictionary_with_inner_transaction():
converter = TransactionsConverter()

inner_transaction = Transaction(
nonce=90,
value=123456789000000000000000000000,
sender="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th",
receiver="erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx",
sender_username="alice",
receiver_username="bob",
gas_limit=80000,
data=b"hello",
chain_id="localnet",
relayer="erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"
)

relayed_transaction = Transaction(
nonce=77,
sender="erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8",
receiver="erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8",
gas_limit=180000,
chain_id="localnet",
inner_transactions=[inner_transaction]
)

tx_as_dict = converter.transaction_to_dictionary(relayed_transaction)
restored_tx = converter.dictionary_to_transaction(tx_as_dict)

assert relayed_transaction == restored_tx
17 changes: 17 additions & 0 deletions multiversx_sdk/core/code_metadata.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from enum import Enum

CODE_METADATA_LENGTH = 2


class ByteZero(Enum):
Upgradeable = 1
Expand All @@ -20,6 +22,21 @@ def __init__(self, upgradeable: bool = True, readable: bool = True, payable: boo
self.payable = payable
self.payable_by_contract = payable_by_contract

@classmethod
def new_from_bytes(cls, data: bytes) -> "CodeMetadata":
if len(data) != CODE_METADATA_LENGTH:
raise ValueError(f"code metadata buffer has length {len(data)}, expected {CODE_METADATA_LENGTH}")

byte_zero = data[0]
byte_one = data[1]

upgradeable = (byte_zero & ByteZero.Upgradeable.value) != 0
readable = (byte_zero & ByteZero.Readable.value) != 0
payable = (byte_one & ByteOne.Payable.value) != 0
payable_by_contract = (byte_one & ByteOne.PayableByContract.value) != 0

return cls(upgradeable, readable, payable, payable_by_contract)

def serialize(self) -> bytes:
data = bytearray([0, 0])

Expand Down
31 changes: 31 additions & 0 deletions multiversx_sdk/core/code_metadata_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@


import pytest

from multiversx_sdk.core.code_metadata import CodeMetadata


def test_code_metadata_new_from_bytes():
metadata = CodeMetadata.new_from_bytes(bytes([0x05, 0x00]))
assert metadata.upgradeable == True
assert metadata.readable == True
assert metadata.payable == False
assert metadata.payable_by_contract == False

metadata = CodeMetadata.new_from_bytes(bytes([0x05, 0x06]))
assert metadata.upgradeable == True
assert metadata.readable == True
assert metadata.payable == True
assert metadata.payable_by_contract == True

metadata = CodeMetadata.new_from_bytes(bytes([0x05, 0x04]))
assert metadata.upgradeable == True
assert metadata.readable == True
assert metadata.payable == False
assert metadata.payable_by_contract == True

metadata = CodeMetadata.new_from_bytes(bytes([0x00, 0x00]))
assert metadata.upgradeable == False
assert metadata.readable == False
assert metadata.payable == False
assert metadata.payable_by_contract == False

with pytest.raises(ValueError, match="code metadata buffer has length 4, expected 2"):
CodeMetadata.new_from_bytes(bytes([0x00, 0x01, 0x02, 0x03]))


def test_code_metadata_serialize():
assert CodeMetadata().serialize() == bytes([0x05, 0x00])
assert CodeMetadata(upgradeable=True, readable=True).serialize() == bytes([0x05, 0x00])
Expand Down
7 changes: 1 addition & 6 deletions multiversx_sdk/core/interfaces.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, Protocol, Sequence
from typing import Optional, Protocol


class IAddress(Protocol):
Expand All @@ -25,11 +25,6 @@ class ITransaction(Protocol):
guardian: str
signature: bytes
guardian_signature: bytes
relayer: str

@property
def inner_transactions(self) -> Sequence["ITransaction"]:
...


class IMessage(Protocol):
Expand Down
2 changes: 0 additions & 2 deletions multiversx_sdk/core/proto/transaction.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,4 @@ message Transaction {
uint32 Options = 13;
bytes GuardAddr = 14;
bytes GuardSignature = 15;
bytes Relayer = 16;
repeated Transaction InnerTransactions = 17;
}
13 changes: 7 additions & 6 deletions multiversx_sdk/core/proto/transaction_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 3 additions & 8 deletions multiversx_sdk/core/proto/transaction_pb2.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from google.protobuf.internal import containers as _containers
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
from typing import ClassVar as _ClassVar, Optional as _Optional

DESCRIPTOR: _descriptor.FileDescriptor

class Transaction(_message.Message):
__slots__ = ["ChainID", "Data", "GasLimit", "GasPrice", "GuardAddr", "GuardSignature", "InnerTransactions", "Nonce", "Options", "RcvAddr", "RcvUserName", "Relayer", "Signature", "SndAddr", "SndUserName", "Value", "Version"]
__slots__ = ["ChainID", "Data", "GasLimit", "GasPrice", "GuardAddr", "GuardSignature", "Nonce", "Options", "RcvAddr", "RcvUserName", "Signature", "SndAddr", "SndUserName", "Value", "Version"]
CHAINID_FIELD_NUMBER: _ClassVar[int]
ChainID: bytes
DATA_FIELD_NUMBER: _ClassVar[int]
Expand All @@ -19,18 +18,14 @@ class Transaction(_message.Message):
GasPrice: int
GuardAddr: bytes
GuardSignature: bytes
INNERTRANSACTIONS_FIELD_NUMBER: _ClassVar[int]
InnerTransactions: _containers.RepeatedCompositeFieldContainer[Transaction]
NONCE_FIELD_NUMBER: _ClassVar[int]
Nonce: int
OPTIONS_FIELD_NUMBER: _ClassVar[int]
Options: int
RCVADDR_FIELD_NUMBER: _ClassVar[int]
RCVUSERNAME_FIELD_NUMBER: _ClassVar[int]
RELAYER_FIELD_NUMBER: _ClassVar[int]
RcvAddr: bytes
RcvUserName: bytes
Relayer: bytes
SIGNATURE_FIELD_NUMBER: _ClassVar[int]
SNDADDR_FIELD_NUMBER: _ClassVar[int]
SNDUSERNAME_FIELD_NUMBER: _ClassVar[int]
Expand All @@ -41,4 +36,4 @@ class Transaction(_message.Message):
VERSION_FIELD_NUMBER: _ClassVar[int]
Value: bytes
Version: int
def __init__(self, Nonce: _Optional[int] = ..., Value: _Optional[bytes] = ..., RcvAddr: _Optional[bytes] = ..., RcvUserName: _Optional[bytes] = ..., SndAddr: _Optional[bytes] = ..., SndUserName: _Optional[bytes] = ..., GasPrice: _Optional[int] = ..., GasLimit: _Optional[int] = ..., Data: _Optional[bytes] = ..., ChainID: _Optional[bytes] = ..., Version: _Optional[int] = ..., Signature: _Optional[bytes] = ..., Options: _Optional[int] = ..., GuardAddr: _Optional[bytes] = ..., GuardSignature: _Optional[bytes] = ..., Relayer: _Optional[bytes] = ..., InnerTransactions: _Optional[_Iterable[_Union[Transaction, _Mapping]]] = ...) -> None: ... # pyright: ignore
def __init__(self, Nonce: _Optional[int] = ..., Value: _Optional[bytes] = ..., RcvAddr: _Optional[bytes] = ..., RcvUserName: _Optional[bytes] = ..., SndAddr: _Optional[bytes] = ..., SndUserName: _Optional[bytes] = ..., GasPrice: _Optional[int] = ..., GasLimit: _Optional[int] = ..., Data: _Optional[bytes] = ..., ChainID: _Optional[bytes] = ..., Version: _Optional[int] = ..., Signature: _Optional[bytes] = ..., Options: _Optional[int] = ..., GuardAddr: _Optional[bytes] = ..., GuardSignature: _Optional[bytes] = ...) -> None: ...
13 changes: 1 addition & 12 deletions multiversx_sdk/core/proto/transaction_serializer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Protocol, Sequence
from typing import Protocol

import multiversx_sdk.core.proto.transaction_pb2 as ProtoTransaction
from multiversx_sdk.core.address import Address
Expand All @@ -21,11 +21,6 @@ class ITransaction(Protocol):
guardian: str
signature: bytes
guardian_signature: bytes
relayer: str

@property
def inner_transactions(self) -> Sequence["ITransaction"]:
...


class ProtoSerializer:
Expand Down Expand Up @@ -71,10 +66,4 @@ def convert_to_proto_message(self, transaction: ITransaction) -> ProtoTransactio
proto_transaction.GuardAddr = Address.new_from_bech32(guardian_address).get_public_key()
proto_transaction.GuardSignature = transaction.guardian_signature

if transaction.relayer != "":
proto_transaction.Relayer = Address.new_from_bech32(transaction.relayer).get_public_key()

proto_transaction.InnerTransactions.extend(
[self.convert_to_proto_message(inner_tx) for inner_tx in transaction.inner_transactions])

return proto_transaction
31 changes: 0 additions & 31 deletions multiversx_sdk/core/proto/transaction_serializer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,34 +86,3 @@ def test_serialized_tx_with_usernames(self):

serialized_transaction = self.proto_serializer.serialize_transaction(transaction)
assert serialized_transaction.hex() == "08cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d086035201545802624051e6cd78fb3ab4b53ff7ad6864df27cb4a56d70603332869d47a5cf6ea977c30e696103e41e8dddf2582996ad335229fdf4acb726564dbc1a0bc9e705b511f06"

def test_serialized_tx_with_inner_txs(self):
inner_transaction = Transaction(
sender=self.carol.label,
receiver=self.alice.label,
gas_limit=50000,
chain_id="T",
nonce=204,
value=1000000000000000000,
sender_username="carol",
receiver_username="alice"
)
inner_transaction.signature = self.carol.secret_key.sign(self.transaction_computer.compute_bytes_for_signing(inner_transaction))

relayed_transaction = Transaction(
sender=self.carol.label,
receiver=self.alice.label,
gas_limit=50000,
chain_id="T",
nonce=204,
value=1000000000000000000,
sender_username="carol",
receiver_username="alice",
relayer=self.carol.label,
inner_transactions=[inner_transaction]
)

relayed_transaction.signature = self.carol.secret_key.sign(self.transaction_computer.compute_bytes_for_signing(
relayed_transaction))
serialized_transaction = self.proto_serializer.serialize_transaction(relayed_transaction)
assert serialized_transaction.hex() == "08cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d0860352015458026240901a6a974d6ab36546e7881c6e0364ec4c61a891aa70e5eb60f818d6c92a39cfa0beac6fab73f503853cfe8fe6149b4be207ddb93788f8450d75a07fa8759d06820120b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba8a01b10108cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d086035201545802624051e6cd78fb3ab4b53ff7ad6864df27cb4a56d70603332869d47a5cf6ea977c30e696103e41e8dddf2582996ad335229fdf4acb726564dbc1a0bc9e705b511f06"
Loading

0 comments on commit ce6f2e0

Please sign in to comment.