Skip to content

Commit

Permalink
move sc query controller to sc controller & get rid of abi interface
Browse files Browse the repository at this point in the history
  • Loading branch information
popenta committed Nov 14, 2024
1 parent e5d99a2 commit 7823fd2
Show file tree
Hide file tree
Showing 23 changed files with 206 additions and 230 deletions.
2 changes: 0 additions & 2 deletions multiversx_sdk/abi/abi_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,6 @@ def __init__(self, name: str) -> None:

@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "ExplicitEnumVariantDefinition":
fields = [FieldDefinition.from_dict(item) for item in data.get("fields", [])]

return cls(
name=data.get("name", "")
)
Expand Down
21 changes: 0 additions & 21 deletions multiversx_sdk/core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ def __init__(self, address: Any) -> None:
super().__init__(f"Bad address: {address}")


class ListsLengthMismatchError(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)


class NotEnoughGasError(Exception):
def __init__(self, gas_limit: int) -> None:
super().__init__(f"Not enough gas provided: {gas_limit}")
Expand All @@ -31,22 +26,6 @@ def __init__(self, message: str) -> None:
super().__init__(message)


class InvalidInnerTransactionError(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)


class ParseTransactionOnNetworkError(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)


class SmartContractQueryError(Exception):
def __init__(self, return_code: str, message: str) -> None:
super().__init__(message)
self.return_code = return_code


class ArgumentSerializationError(Exception):
def __init__(self, message: str = "Unable to encode arguments: unsupported format or missing ABI file") -> None:
super().__init__(message)
9 changes: 2 additions & 7 deletions multiversx_sdk/core/transaction_events_parser.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
from types import SimpleNamespace
from typing import Protocol

from multiversx_sdk.abi.abi import Abi
from multiversx_sdk.core.transaction_on_network import TransactionEvent


class IAbi(Protocol):
def decode_event(self, event_name: str, topics: list[bytes], additional_data: list[bytes]) -> SimpleNamespace:
...


class TransactionEventsParser:
def __init__(self, abi: IAbi, first_topic_as_identifier: bool = True) -> None:
def __init__(self, abi: Abi, first_topic_as_identifier: bool = True) -> None:
self.abi = abi
# By default, we consider that the first topic is the event identifier.
# This is true for log entries emitted by smart contracts:
Expand Down
4 changes: 2 additions & 2 deletions multiversx_sdk/delegation/delegation_transactions_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from multiversx_sdk.abi import Serializer
from multiversx_sdk.abi.biguint_value import BigUIntValue
from multiversx_sdk.abi.string_value import StringValue
from multiversx_sdk.builders.transaction_builder import TransactionBuilder
from multiversx_sdk.core import Address, Transaction
from multiversx_sdk.core.constants import DELEGATION_MANAGER_SC_ADDRESS
from multiversx_sdk.core.errors import ListsLengthMismatchError
from multiversx_sdk.core.interfaces import IValidatorPublicKey
from multiversx_sdk.builders.transaction_builder import TransactionBuilder
from multiversx_sdk.delegation.errors import ListsLengthMismatchError


class IConfig(Protocol):
Expand Down
3 changes: 3 additions & 0 deletions multiversx_sdk/delegation/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class ListsLengthMismatchError(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)
19 changes: 3 additions & 16 deletions multiversx_sdk/entrypoints/entrypoints.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Any, Optional, Protocol, Tuple, Union
from typing import Optional, Tuple, Union

from multiversx_sdk.abi.abi import Abi
from multiversx_sdk.account_management import AccountController
from multiversx_sdk.accounts import Account
from multiversx_sdk.core import (Address, Message, MessageComputer,
Expand All @@ -21,20 +22,6 @@
from multiversx_sdk.wallet.user_verifer import UserVerifier


class IAbi(Protocol):
def encode_endpoint_input_parameters(self, endpoint_name: str, values: list[Any]) -> list[bytes]:
...

def encode_constructor_input_parameters(self, values: list[Any]) -> list[bytes]:
...

def encode_upgrade_constructor_input_parameters(self, values: list[Any]) -> list[bytes]:
...

def decode_endpoint_output_parameters(self, endpoint_name: str, encoded_values: list[bytes]) -> list[Any]:
...


class NetworkEntrypoint:
def __init__(self,
network_provider_url: str,
Expand Down Expand Up @@ -113,7 +100,7 @@ def create_account_controller(self) -> AccountController:
def create_relayed_controller(self) -> RelayedController:
return RelayedController(self.chain_id)

def create_smart_contract_controller(self, abi: Optional[IAbi] = None) -> SmartContractController:
def create_smart_contract_controller(self, abi: Optional[Abi] = None) -> SmartContractController:
return SmartContractController(self.chain_id, self.network_provider, abi)

def create_token_management_controller(self) -> TokenManagementController:
Expand Down
2 changes: 1 addition & 1 deletion multiversx_sdk/entrypoints/entrypoints_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def test_contract_flow(self):
tx_hash = self.entrypoint.send_transaction(transaction)
self.entrypoint.await_completed_transaction(tx_hash)

query_result = controller.query_contract(
query_result = controller.query(
contract=contract_address,
function="getSum",
arguments=[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def test_get_sc_invoking_tx(self):

def test_query_contract(self):
query = SmartContractQuery(
contract="erd1qqqqqqqqqqqqqpgqqy34h7he2ya6qcagqre7ur7cc65vt0mxrc8qnudkr4",
contract=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqqy34h7he2ya6qcagqre7ur7cc65vt0mxrc8qnudkr4"),
function="getSum",
arguments=[],
)
Expand Down
4 changes: 2 additions & 2 deletions multiversx_sdk/network_providers/http_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@

def smart_contract_query_to_vm_query_request(query: SmartContractQuery) -> dict[str, Any]:
request: dict[str, Any] = {
"scAddress": query.contract,
"scAddress": query.contract.to_bech32(),
"funcName": query.function,
"value": str(query.value if query.value else 0),
"args": [arg.hex() for arg in query.arguments]
}

if query.caller:
request["caller"] = query.caller
request["caller"] = query.caller.to_bech32()

return request

Expand Down
4 changes: 2 additions & 2 deletions multiversx_sdk/network_providers/proxy_network_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ def get_definition_of_fungible_token(self, token_identifier: str) -> FungibleTok
"""Fetches the definition of a fungible token."""
encoded_identifier = token_identifier.encode()
query = SmartContractQuery(
contract=ESDT_CONTRACT_ADDRESS,
contract=Address.new_from_bech32(ESDT_CONTRACT_ADDRESS),
function="getTokenProperties",
arguments=[encoded_identifier],
)
Expand All @@ -261,7 +261,7 @@ def get_definition_of_tokens_collection(self, collection_name: str) -> TokensCol
"""Fetches the definition of a tokens collection."""
encoded_identifier = collection_name.encode()
query = SmartContractQuery(
contract=ESDT_CONTRACT_ADDRESS,
contract=Address.new_from_bech32(ESDT_CONTRACT_ADDRESS),
function="getTokenProperties",
arguments=[encoded_identifier],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def test_get_transaction_status(self):

def test_query_contract(self):
query = SmartContractQuery(
contract="erd1qqqqqqqqqqqqqpgqqy34h7he2ya6qcagqre7ur7cc65vt0mxrc8qnudkr4",
contract=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqqy34h7he2ya6qcagqre7ur7cc65vt0mxrc8qnudkr4"),
function="getSum",
arguments=[]
)
Expand Down
3 changes: 3 additions & 0 deletions multiversx_sdk/relayed/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class InvalidInnerTransactionError(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)
2 changes: 1 addition & 1 deletion multiversx_sdk/relayed/relayed_transactions_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from multiversx_sdk.abi import AddressValue, BigUIntValue, Serializer
from multiversx_sdk.abi.bytes_value import BytesValue
from multiversx_sdk.core import Address, Transaction
from multiversx_sdk.core.errors import InvalidInnerTransactionError
from multiversx_sdk.relayed.errors import InvalidInnerTransactionError


class IConfig(Protocol):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest

from multiversx_sdk.core import Address, Transaction, TransactionComputer
from multiversx_sdk.core.errors import InvalidInnerTransactionError
from multiversx_sdk.core.transactions_factory_config import \
TransactionsFactoryConfig
from multiversx_sdk.relayed.errors import InvalidInnerTransactionError
from multiversx_sdk.relayed.relayed_transactions_factory import \
RelayedTransactionsFactory
from multiversx_sdk.testutils.wallets import load_wallets
Expand Down
10 changes: 10 additions & 0 deletions multiversx_sdk/smart_contracts/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

class SmartContractQueryError(Exception):
def __init__(self, return_code: str, message: str) -> None:
super().__init__(message)
self.return_code = return_code


class ArgumentSerializationError(Exception):
def __init__(self, message: str = "Unable to encode arguments: unsupported format or missing ABI file") -> None:
super().__init__(message)
110 changes: 73 additions & 37 deletions multiversx_sdk/smart_contracts/smart_contract_controller.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
from pathlib import Path
from typing import Any, Optional, Protocol, Sequence, Union

from multiversx_sdk.abi.abi import Abi
from multiversx_sdk.abi.serializer import Serializer
from multiversx_sdk.abi.typesystem import (is_list_of_bytes,
is_list_of_typed_values)
from multiversx_sdk.core import (Address, TokenTransfer, Transaction,
TransactionComputer, TransactionOnNetwork)
from multiversx_sdk.core.interfaces import IAccount
from multiversx_sdk.core.transactions_factory_config import \
TransactionsFactoryConfig
from multiversx_sdk.network_providers.resources import AwaitingOptions
from multiversx_sdk.smart_contracts.smart_contract_queries_controller import \
SmartContractQueriesController
from multiversx_sdk.smart_contracts.errors import SmartContractQueryError
from multiversx_sdk.smart_contracts.smart_contract_query import (
SmartContractQuery, SmartContractQueryResponse)
from multiversx_sdk.smart_contracts.smart_contract_transactions_factory import \
SmartContractTransactionsFactory
from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import \
SmartContractTransactionsOutcomeParser
from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser_types import \
SmartContractDeployOutcome
from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser_types import (
ParsedSmartContractCallOutcome, SmartContractDeployOutcome)


class INetworkProvider(Protocol):
Expand All @@ -27,32 +30,15 @@ def await_transaction_completed(self, transaction_hash: Union[str, bytes], optio
...


class IAbi(Protocol):
def encode_endpoint_input_parameters(self, endpoint_name: str, values: list[Any]) -> list[bytes]:
...

def encode_constructor_input_parameters(self, values: list[Any]) -> list[bytes]:
...

def encode_upgrade_constructor_input_parameters(self, values: list[Any]) -> list[bytes]:
...

def decode_endpoint_output_parameters(self, endpoint_name: str, encoded_values: list[bytes]) -> list[Any]:
...


class SmartContractController:
def __init__(self, chain_id: str, network_provider: INetworkProvider, abi: Optional[IAbi] = None) -> None:
def __init__(self, chain_id: str, network_provider: INetworkProvider, abi: Optional[Abi] = None) -> None:
self.abi = abi
self.factory = SmartContractTransactionsFactory(
TransactionsFactoryConfig(chain_id), abi=self.abi)
self.parser = SmartContractTransactionsOutcomeParser()
self.query_controller = SmartContractQueriesController(
network_provider=network_provider,
abi=self.abi
)
self.network_provider = network_provider
self.tx_computer = TransactionComputer()
self.serializer = Serializer()

def create_transaction_for_deploy(self,
sender: IAccount,
Expand Down Expand Up @@ -144,22 +130,72 @@ def create_transaction_for_execute(self,

return transaction

def parse_execute(self, transaction_on_network: TransactionOnNetwork, function: Optional[str] = None) -> list[Any]:
raise NotImplementedError("This method is not yet implemented")
def parse_execute(self, transaction_on_network: TransactionOnNetwork, function: Optional[str] = None) -> ParsedSmartContractCallOutcome:
return self.parser.parse_execute(transaction_on_network, function)

def await_completed_execute(self, transaction_hash: Union[str, bytes]) -> ParsedSmartContractCallOutcome:
transaction = self.network_provider.await_transaction_completed(transaction_hash)
return self.parse_execute(transaction, transaction.function)

def query(self,
contract: Address,
function: str,
arguments: list[Any],
caller: Optional[Address] = None,
value: Optional[int] = None) -> list[Any]:
"""It calls `create_query()`, `run_query()` and `parse_query_response()` in one go."""
query = self.create_query(
contract=contract,
function=function,
arguments=arguments,
caller=caller,
value=value
)

query_response = self.run_query(query)
self._raise_for_status(query_response)
return self.parse_query_response(query_response)

def await_completed_execute(self, transaction_hash: Union[str, bytes]) -> list[Any]:
raise NotImplementedError("This feature is not yet implemented")
def _raise_for_status(self, query_response: SmartContractQueryResponse):
is_ok = query_response.return_code == "ok"
if not is_ok:
raise SmartContractQueryError(query_response.return_code, query_response.return_message)

def query_contract(self,
contract: Address,
function: str,
arguments: list[Any],
caller: Optional[Address] = None,
value: Optional[int] = None) -> list[Any]:
return self.query_controller.query(
contract=contract.to_bech32(),
def create_query(self,
contract: Address,
function: str,
arguments: list[Any],
caller: Optional[Address] = None,
value: Optional[int] = None) -> SmartContractQuery:
prepared_arguments = self._encode_arguments(function, arguments)

return SmartContractQuery(
contract=contract,
function=function,
arguments=arguments,
caller=caller.to_bech32() if caller else None,
arguments=prepared_arguments,
caller=caller,
value=value
)

def _encode_arguments(self, function_name: str, args: list[Any]) -> list[bytes]:
if self.abi:
return self.abi.encode_endpoint_input_parameters(function_name, args)

if is_list_of_typed_values(args):
return self.serializer.serialize_to_parts(args)

if is_list_of_bytes(args):
return args

raise Exception("Can't serialize arguments")

def run_query(self, query: SmartContractQuery) -> SmartContractQueryResponse:
return self.network_provider.query_contract(query)

def parse_query_response(self, response: SmartContractQueryResponse) -> list[Any]:
encoded_values = response.return_data_parts

if self.abi:
return self.abi.decode_endpoint_output_parameters(response.function, encoded_values)

return encoded_values
Loading

0 comments on commit 7823fd2

Please sign in to comment.