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

Implement oracle commands from Neo-Express to the NeoTestRunner interface #1097

Merged
merged 2 commits into from
Jul 18, 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
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ def __init__(self):
identifier = 'request'
syscall = 'request'
args: Dict[str, Variable] = {'url': Variable(Type.str),
'request_filter': Variable(Type.union.build([Type.str,
Type.none])),
'request_filter': Variable(Type.str),
'callback': Variable(Type.str),
'user_data': Variable(Type.any),
'gas_for_response': Variable(Type.int)}
Expand Down
31 changes: 31 additions & 0 deletions boa3_test/test_drive/model/network/payloads/oracleresponse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

from typing import Dict, Any

from boa3_test.test_drive.model.network.payloads.transactionattribute import TransactionAttribute, \
TransactionAttributeType


class OracleResponse(TransactionAttribute):
def __init__(self, id_: int, code: str, result: str):
super().__init__(TransactionAttributeType.ORACLE_RESPONSE)
self._id = id_
self._code = code
self._result = result

def to_json(self) -> Dict[str, Any]:
import base64
import json
json_response = super().to_json()

json_response['id'] = self._id
json_response['code'] = self._code
json_response['result'] = json.loads(base64.b64decode(self._result))

return json_response

@staticmethod
def from_json(json: Dict[str, Any]) -> OracleResponse:
oracle_response: OracleResponse = OracleResponse(json['id'], json['code'], json['result'])

return oracle_response
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from boa3.internal.neo3.core.types import UInt256
from boa3.internal.neo3.vm import VMState
from boa3_test.test_drive.model.network.payloads.signer import Signer
from boa3_test.test_drive.model.network.payloads.transactionattribute import TransactionAttribute
from boa3_test.test_drive.model.network.payloads.witness import Witness
from boa3_test.test_drive.model.smart_contract.contractcollection import ContractCollection
from boa3_test.test_drive.model.smart_contract.triggertype import TriggerType
Expand All @@ -22,7 +23,7 @@ def __init__(self, tx_hash: Union[UInt256, bytes], script: bytes, signers: List[

self._signers: List[Signer] = signers if signers is not None else []
self._witnesses: List[Witness] = witnesses if witnesses is not None else []
self._attributes = []
self._attributes: List[TransactionAttribute] = []

def __new__(cls, *args, **kwargs):
return super().__new__(cls)
Expand Down Expand Up @@ -55,7 +56,12 @@ def from_json(cls, json: Dict[str, Any]) -> TestTransaction:
tx = object.__new__(cls) # init was causing errors with inherited classes
tx._hash = tx_hash
tx._script = script

tx._attributes = []
if 'attributes' in json:
tx._attributes = [TransactionAttribute.from_json(attr) for attr in json['attributes']]
else:
tx._attributes = []

if 'signers' in json:
signers_json = json['signers']
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from __future__ import annotations

from typing import Dict, Any


class TransactionAttributeType:

ORACLE_RESPONSE = 'OracleResponse'
NOT_VALID_BEFORE = 'NotValidBefore'
HIGH_PRIORITY_ATTRIBUTE = 'HighPriorityAttribute'


class TransactionAttribute:
def __init__(self, type_: str):
self._type = type_

def to_json(self) -> Dict[str, Any]:
return {
'type': self._type,
}

@staticmethod
def from_json(json: Dict[str, Any]) -> TransactionAttribute:
if json['type'] == TransactionAttributeType.ORACLE_RESPONSE:
from boa3_test.test_drive.model.network.payloads.oracleresponse import OracleResponse
tx_attr = OracleResponse.from_json(json)
else:
tx_attr = TransactionAttribute(json['type'])

return tx_attr
8 changes: 8 additions & 0 deletions boa3_test/test_drive/neoxp/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,11 @@ def has_new_deploys(self):
return next((True for command in self._instructions
if isinstance(command, neoxp.neoxp.contract.deploy.ContractDeployCommand)),
False)

def oracle_enable(self, account: Account):
self._instructions.append(neoxp.oracle.enable(account)
)

def oracle_response(self, url: str, response_path: str, request_id: int = None):
self._instructions.append(neoxp.oracle.response(url, response_path,
request_id=request_id))
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
create,
checkpoint,
fastforward,
oracle,
reset,
show,
transfer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ def cli_command(self) -> str:
command.extend(o)

for arg in self._args:
if ' ' in arg:
arg = f'"{arg}"'
command.append(arg)

return ' '.join(command)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
__all__ = [
'OracleEnableCommand',
'OracleListCommand',
'OracleRequestsCommand',
'OracleResponseCommand',
]

from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.enable import OracleEnableCommand
from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.list import OracleListCommand
from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.requests import OracleRequestsCommand
from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.response import OracleResponseCommand
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Dict

from boa3_test.test_drive.model.wallet.account import Account
from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.ioraclecommand import IOracleCommand


class OracleEnableCommand(IOracleCommand):
def __init__(self, account: Account,
trace: bool = False,
neo_express_data_file: str = None):

self.trace = trace
self.input = neo_express_data_file

command_id = 'enable'
args = [
account.get_identifier(),
]

super().__init__(command_id, args)

def _get_options(self) -> Dict[str, str]:
options = super()._get_options()

if self.trace:
options['--trace'] = ''

return options
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import abc
from typing import List

from boa3_test.test_drive.neoxp.command.neoexpresscommand.neoexpresscommand import NeoExpressCommand


class IOracleCommand(abc.ABC, NeoExpressCommand):
def __init__(self, sub_command_id: str, args: List[str] = None):
command_id = 'oracle'
if len(sub_command_id) > 0:
command_id = f'{command_id} {sub_command_id}'

super().__init__(command_id, args)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Dict

from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.ioraclecommand import IOracleCommand


class OracleListCommand(IOracleCommand):
def __init__(self,
neo_express_data_file: str = None):

self.input = neo_express_data_file

command_id = 'list'

super().__init__(command_id)

def _get_options(self) -> Dict[str, str]:
return super()._get_options()
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Dict

from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.ioraclecommand import IOracleCommand


class OracleRequestsCommand(IOracleCommand):
def __init__(self,
neo_express_data_file: str = None):

self.input = neo_express_data_file

command_id = 'requests'

super().__init__(command_id)

def _get_options(self) -> Dict[str, str]:
return super()._get_options()
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import Dict, Optional

from boa3_test.test_drive.neoxp.command.neoexpresscommand.oracle.ioraclecommand import IOracleCommand


class OracleResponseCommand(IOracleCommand):
def __init__(self, url: str, response_path: str,
request_id: Optional[int] = None,
trace: bool = False,
neo_express_data_file: str = None):

self.request_id = request_id
self.trace = trace
self.input = neo_express_data_file

command_id = 'response'
args = [
url,
response_path,
]

super().__init__(command_id, args)

def _get_options(self) -> Dict[str, str]:
options = super()._get_options()

if self.request_id:
options[f'--request_id:{self.request_id}'] = ''

if self.trace:
options['--trace'] = ''

return options
1 change: 1 addition & 0 deletions boa3_test/test_drive/neoxp/command/neoxp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from boa3_test.test_drive.model.wallet.account import Account
from boa3_test.test_drive.neoxp.command import neoexpresscommand as neoxp
from boa3_test.test_drive.neoxp.command import neoxp_contract as contract
from boa3_test.test_drive.neoxp.command import neoxp_oracle as oracle
from boa3_test.test_drive.neoxp.command.neoexpresscommand import NeoExpressCommand


Expand Down
20 changes: 20 additions & 0 deletions boa3_test/test_drive/neoxp/command/neoxp_oracle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from boa3_test.test_drive.model.wallet.account import Account
from boa3_test.test_drive.neoxp.command import neoexpresscommand as neoxp
from boa3_test.test_drive.neoxp.command.neoexpresscommand import NeoExpressCommand


def enable(account: Account) -> NeoExpressCommand:
return neoxp.oracle.OracleEnableCommand(account)


def response(url: str, response_path: str, request_id: int = None) -> NeoExpressCommand:
return neoxp.oracle.OracleResponseCommand(url, response_path,
request_id=request_id)


def requests() -> NeoExpressCommand:
return neoxp.oracle.OracleRequestsCommand()


def list() -> NeoExpressCommand:
return neoxp.oracle.OracleListCommand()
17 changes: 17 additions & 0 deletions boa3_test/test_drive/neoxp/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,20 @@ def run_neo_express_cli(command: neoxp.NeoExpressCommand) -> Tuple[str, str]:
text=True)
cli_result = process.communicate()
return cli_result


def oracle_response(neoxp_path: str, url: str, response_path: str, request_id: int = None,
check_point_file: str = None) -> List[UInt256]:
command = neoxp.oracle.OracleResponseCommand(url, response_path, request_id, neo_express_data_file=neoxp_path)

with _NEOXP_CONFIG_LOCK:
if isinstance(check_point_file, str):
reset_neo_express_instance(neoxp_path, check_point_file)
stdout, stderr = run_neo_express_cli(command)

import re
from boa3.internal.neo import from_hex_str

oracle_response_submitted = re.findall(r"0x\w{64}", stdout)

return [UInt256(from_hex_str(tx)) for tx in oracle_response_submitted]
17 changes: 17 additions & 0 deletions boa3_test/test_drive/testrunner/neo_test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,17 @@ def get_block(self, block_hash_or_index: Union[UInt256, bytes, int]) -> Optional
return block

def get_transaction(self, tx_hash: Union[UInt256, bytes]) -> Optional[Transaction]:
if isinstance(tx_hash, bytes):
tx_hash = UInt256(tx_hash)

check_point_path = self.get_full_path(self._CHECKPOINT_FILE)
return neoxp_utils.get_transaction(self._neoxp_abs_path, tx_hash,
check_point_file=check_point_path)

def get_transaction_result(self, tx_hash: Union[UInt256, bytes]) -> Optional[TransactionLog]:
if isinstance(tx_hash, bytes):
tx_hash = UInt256(tx_hash)

check_point_path = self.get_full_path(self._CHECKPOINT_FILE)
return neoxp_utils.get_transaction_log(self._neoxp_abs_path, tx_hash,
check_point_file=check_point_path,
Expand Down Expand Up @@ -459,3 +465,14 @@ def _run_command_line(self, args: List[str]) -> Tuple[str, str]:

def increase_block(self, block_to_mint: int = None, time_interval_in_secs: int = 0):
self._batch.mint_block(block_to_mint, time_interval_in_secs)

def oracle_enable(self, account: Account):
self._batch.oracle_enable(account)

def oracle_response(self, url: str, response_path: str, request_id: int = None) -> List[UInt256]:
check_point_path = self.get_full_path(self._CHECKPOINT_FILE)

# add to command to batch file and get the tx id
self._batch.oracle_response(url, response_path, request_id=request_id)
return neoxp_utils.oracle_response(self._neoxp_abs_path, url, response_path, request_id,
check_point_file=check_point_path)
4 changes: 2 additions & 2 deletions boa3_test/test_sc/native_test/oracle/ImportInteropOracle.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Any, Union
from typing import Any

from boa3.builtin import interop
from boa3.builtin.compile_time import public


@public
def oracle_call(url: str, request_filter: Union[str, None], callback: str, user_data: Any, gas_for_response: int):
def oracle_call(url: str, request_filter: str, callback: str, user_data: Any, gas_for_response: int):
interop.oracle.Oracle.request(url, request_filter, callback, user_data, gas_for_response)


Expand Down
4 changes: 2 additions & 2 deletions boa3_test/test_sc/native_test/oracle/ImportOracle.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Any, Union
from typing import Any

from boa3.builtin.compile_time import public
from boa3.builtin.interop import oracle


@public
def oracle_call(url: str, request_filter: Union[str, None], callback: str, user_data: Any, gas_for_response: int):
def oracle_call(url: str, request_filter: str, callback: str, user_data: Any, gas_for_response: int):
oracle.Oracle.request(url, request_filter, callback, user_data, gas_for_response)


Expand Down
Loading