diff --git a/.idea/misc.xml b/.idea/misc.xml
index 58ebae9..5e70f00 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/tonpy.iml b/.idea/tonpy.iml
index e5ec395..fa33167 100644
--- a/.idea/tonpy.iml
+++ b/.idea/tonpy.iml
@@ -5,8 +5,9 @@
+
-
+
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 6f682a2..0b96bfb 100644
--- a/setup.py
+++ b/setup.py
@@ -31,7 +31,7 @@ def finalize_options(self):
setup(
name="tonpy" if not IS_DEV else "tonpy-dev",
- version="0.0.0.1.2b0" if not IS_DEV else "0.0.0.4.7b1",
+ version="0.0.0.1.2b0" if not IS_DEV else "0.0.0.4.7c1",
author="Disintar LLP",
author_email="andrey@head-labs.com",
description="Types / API for TON blockchain",
diff --git a/src/tonpy/blockscanner/blockscanner.py b/src/tonpy/blockscanner/blockscanner.py
index a58ba1f..1021486 100644
--- a/src/tonpy/blockscanner/blockscanner.py
+++ b/src/tonpy/blockscanner/blockscanner.py
@@ -108,13 +108,19 @@ def process_subscriptions(data,
raise NotImplementedError("Emulation not supported yet")
-def get_mega_libs(num_try=100):
+def get_mega_libs(dton_key, num_try=100):
cur = 0
while cur < num_try:
try:
query = '''query{mega_libs_cell}'''
- response = requests.post("https://dton.io/graphql", json={'query': query})
+
+ if dton_key is not None:
+ url = f"https://dton.io/{dton_key}/graphql"
+ else:
+ url = f"https://dton.io/graphql"
+
+ response = requests.post(url, json={'query': query})
return response.json()['data']['mega_libs_cell']
except Exception as e:
logger.error(f"Can't get dton.io/graphql: {e}, {tb.format_exc()}")
@@ -498,7 +504,8 @@ def __init__(self,
live_load_enable: bool = False,
load_chunks: typing.List[typing.Tuple[int, int]] = None,
allow_skip_mc_in_live: bool = True,
- blocks_to_load: List[BlockIdExt] = None):
+ blocks_to_load: List[BlockIdExt] = None,
+ dton_key: str = None):
"""
:param lcparams: Params for LiteClient
@@ -583,7 +590,7 @@ def __init__(self,
self.account_subscriptions = account_subscriptions
self.emulate_before_output = emulate_before_output
self.known_key_blocks = {}
- self.mega_libs = get_mega_libs()
+ self.mega_libs = get_mega_libs(dton_key)
self.process_raw = raw_process is not None
if self.process_raw:
@@ -901,7 +908,7 @@ def load_historical(self):
if self.loglevel > 1:
logger.debug(f"Start get mega libs: {time() - key_blocks_start_at}")
- mega_libs = get_mega_libs()
+ mega_libs = self.mega_libs
for i in shards_data:
i['libs'] = mega_libs
diff --git a/src/tonpy/tests/test_vmdict_large_keys.py b/src/tonpy/tests/test_vmdict_large_keys.py
index 6ad8c68..1bd470e 100644
--- a/src/tonpy/tests/test_vmdict_large_keys.py
+++ b/src/tonpy/tests/test_vmdict_large_keys.py
@@ -7,6 +7,9 @@
import pytest
+from tonpy import LiteClient
+from tonpy.autogen.block import Account
+
path_root = Path(__file__).parents[2]
sys.path.append(str(path_root))
@@ -62,7 +65,7 @@ def test_set_get_large():
d.set_ref(CellBuilder().store_uint(1, 8).store_uint(2 ** 254, 256).end_cell().begin_parse(), v2)
d.set_builder(CellBuilder().store_uint(2, 8).store_uint(2 ** 254, 256).end_cell().begin_parse(),
- CellBuilder().store_uint(0, 8))
+ CellBuilder().store_uint(0, 8))
value = d.lookup(CellBuilder().store_uint(0, 8).store_uint(2 ** 254, 256).end_cell().begin_parse())
assert value.get_hash() == v1.get_hash()
diff --git a/src/tonpy/tvm/c7.py b/src/tonpy/tvm/c7.py
index fd131c1..f89ea4c 100644
--- a/src/tonpy/tvm/c7.py
+++ b/src/tonpy/tvm/c7.py
@@ -1,8 +1,12 @@
from typing import Union, List
-from tonpy.types import Cell, CellSlice, Stack, begin_cell, Address
+from tonpy.types.cell import Cell
+from tonpy.types.cellslice import CellSlice
+from tonpy.types.cellbuilder import begin_cell
+from tonpy.types.address import Address
from datetime import datetime
from tonpy.types.blockid import BlockIdExt
+from tonpy.types.stack import Stack
class C7:
diff --git a/src/tonpy/tvm/emulator.py b/src/tonpy/tvm/emulator.py
index 2a23ab5..ff79886 100644
--- a/src/tonpy/tvm/emulator.py
+++ b/src/tonpy/tvm/emulator.py
@@ -2,7 +2,7 @@
from tonpy.libs.python_ton import PyEmulator
-from tonpy import Stack, StackEntry
+from tonpy.types.stack import Stack, StackEntry
from tonpy.types import VmDict, Cell, CellSlice, begin_cell
from tonpy.types.blockid import BlockId
from typing import Union, Tuple, List
diff --git a/src/tonpy/tvm/tvm.py b/src/tonpy/tvm/tvm.py
index 6e574ca..75025fb 100644
--- a/src/tonpy/tvm/tvm.py
+++ b/src/tonpy/tvm/tvm.py
@@ -58,7 +58,13 @@ def clear_stack(self) -> bool:
def fetch_detailed_step_info(self) -> None:
self.vm_steps_detailed = [StepInfo(i) for i in self.tvm.get_stacks()]
ops = self.tvm.get_ops()
- assert len(ops) == len(self.vm_steps_detailed)
+ if len(ops) != len(self.vm_steps_detailed):
+ if len(self.vm_steps_detailed) - len(ops) == 1:
+ self.vm_steps_detailed = self.vm_steps_detailed[1:]
+ else:
+ logger.error(f"VM steps: {len(ops)} != {len(self.vm_steps_detailed)}")
+ return
+
for i, op in enumerate(ops):
self.vm_steps_detailed[i].next_op = op
@@ -113,6 +119,50 @@ def exit_code(self) -> int:
return ~self.tvm.exit_code
return self.tvm.exit_code
+ def exit_code_description(self):
+ exit_codes = {
+ 0: {"Phase": "Compute Phase", "Description": "Standard successful execution exit code."},
+ 1: {"Phase": "Compute Phase", "Description": "Alternative successful execution exit code."},
+ 2: {"Phase": "Compute Phase",
+ "Description": "Stack underflow. Last op-code consumed more elements than there are on the stacks."},
+ 3: {"Phase": "Compute Phase",
+ "Description": "Stack overflow. More values have been stored on a stack than allowed by this version of TVM."},
+ 4: {"Phase": "Compute Phase",
+ "Description": "Integer overflow. Integer does not fit into −2^256 ≤ x < 2^256 or a division by zero has occurred."},
+ 5: {"Phase": "Compute Phase", "Description": "Integer out of expected range."},
+ 6: {"Phase": "Compute Phase",
+ "Description": "Invalid opcode. Instruction is unknown in the current TVM version."},
+ 7: {"Phase": "Compute Phase",
+ "Description": "Type check error. An argument to a primitive is of an incorrect value type."},
+ 8: {"Phase": "Compute Phase",
+ "Description": "Cell overflow. Writing to builder is not possible since after operation there would be more than 1023 bits or 4 references."},
+ 9: {"Phase": "Compute Phase",
+ "Description": "Cell underflow. Read from slice primitive tried to read more bits or references than there are."},
+ 10: {"Phase": "Compute Phase",
+ "Description": "Dictionary error. Error during manipulation with dictionary (hashmaps)."},
+ 11: {"Phase": "Compute Phase",
+ "Description": "Most often caused by trying to call get-method whose id wasn't found in the code (missing method_id modifier or wrong get-method name specified when trying to call it)."},
+ 12: {"Phase": "Compute Phase", "Description": "Thrown by TVM in situations deemed impossible."},
+ 13: {"Phase": "Compute Phase",
+ "Description": "Out of gas error. Thrown by TVM when the remaining gas becomes negative."},
+ 32: {"Phase": "Action Phase",
+ "Description": "Action list is invalid. Set during action phase if c5 register after execution contains unparsable object."},
+ 33: {"Phase": "Action Phase", "Description": "Action list is too long."},
+ 34: {"Phase": "Action Phase",
+ "Description": "Action is invalid or not supported. Set during action phase if current action cannot be applied."},
+ 35: {"Phase": "Action Phase", "Description": "Invalid Source address in outbound message."},
+ 36: {"Phase": "Action Phase", "Description": "Invalid Destination address in outbound message."},
+ 37: {"Phase": "Action Phase",
+ "Description": "Not enough TON. Message sends too much TON (or there is not enough TON after deducting fees)."},
+ 38: {"Phase": "Action Phase", "Description": "Not enough extra-currencies."},
+ 40: {"Phase": "Action Phase",
+ "Description": "Not enough funds to process a message. This error is thrown when there is only enough gas to cover part of the message, but does not cover it completely."},
+ 43: {"Phase": "Action Phase",
+ "Description": "The maximum number of cells in the library is exceeded or the maximum depth of the Merkle tree is exceeded."}
+ }
+
+ return exit_codes[self.exit_code]
+
@property
def vm_steps(self) -> int:
return self.tvm.vm_steps
diff --git a/src/tonpy/types/__init__.py b/src/tonpy/types/__init__.py
index 6c3a3bf..89f98cb 100644
--- a/src/tonpy/types/__init__.py
+++ b/src/tonpy/types/__init__.py
@@ -2,7 +2,7 @@
from tonpy.types.cell import Cell
from tonpy.types.cellslice import CellSlice
-from tonpy.types.cellbuilder import CellBuilder
+from tonpy.types.cellbuilder import CellBuilder, begin_cell
from tonpy.types.vmdict import VmDict, TypedVmDict, TypedDataWithExtra, DataWithExtra, AugmentedData, TypedAugmentedData
from tonpy.types.tlb import TLB, RecordBase
from tonpy.types.tlb_types import RefT, NatWidth, TLBComplex, Int, UInt, Bits, NatLeq, NatLess
@@ -13,7 +13,3 @@
from tonpy.types.liteclient import *
from tonpy.types.address import *
from tonpy.types.vmdict_extra import *
-
-
-def begin_cell():
- return CellBuilder()
diff --git a/src/tonpy/types/address.py b/src/tonpy/types/address.py
index ce9025c..6346d39 100644
--- a/src/tonpy/types/address.py
+++ b/src/tonpy/types/address.py
@@ -67,6 +67,7 @@ def shard_prefix(self, size) -> int:
return self.my_address.shard_prefix(size)
def to_cs(self) -> CellSlice:
+ from tonpy.types.cellbuilder import CellBuilder
return CellBuilder().store_address(self).end_cell().begin_parse()
def __eq__(self, other):
diff --git a/src/tonpy/types/cellbuilder.py b/src/tonpy/types/cellbuilder.py
index ea7be17..7ce5955 100644
--- a/src/tonpy/types/cellbuilder.py
+++ b/src/tonpy/types/cellbuilder.py
@@ -418,3 +418,7 @@ def __repr__(self):
r = self.refs
return f""
+
+
+def begin_cell():
+ return CellBuilder()
diff --git a/src/tonpy/types/liteclient.py b/src/tonpy/types/liteclient.py
index c573081..cda5398 100644
--- a/src/tonpy/types/liteclient.py
+++ b/src/tonpy/types/liteclient.py
@@ -8,8 +8,12 @@
from tonpy.libs.python_ton import PyLiteClient, ipv4_int_to_str, globalSetVerbosity, BlockId as ton_BlockId, \
BlockIdExt as ton_BlockIdExt
+from tonpy.types.lite_utils.constants import MASTER_SHARD
+from tonpy.types.cellbuilder import CellBuilder
+from tonpy.types.stack import Stack
from tonpy.types.cell import Cell
from tonpy.types.address import Address
+from tonpy.tvm.tvm import TVM, method_name_to_id
from tonpy.types.keys import PublicKey
from base64 import b64decode
@@ -74,6 +78,23 @@ def __init__(self, ac):
self.gen_lt = ac.gen_lt
self.gen_utime = ac.gen_utime
+ def to_shard_state(self):
+ if not self.root.is_null():
+ return CellBuilder() \
+ .store_ref(self.root) \
+ .store_uint(int(self.last_trans_hash, 16), 256) \
+ .store_uint(self.last_trans_lt, 64).end_cell()
+ else:
+ return CellBuilder() \
+ .store_ref(CellBuilder().store_uint(0, 1).end_cell()) \
+ .store_uint(int(self.last_trans_hash, 16), 256) \
+ .store_uint(self.last_trans_lt, 64) \
+ .end_cell()
+
+ def get_parsed(self):
+ from tonpy.autogen.block import Account
+ return Account().cell_unpack(self.root, rec_unpack=True)
+
class BlockHdrInfo:
__slots__ = ['blk_id', 'proof', 'virt_blk_root', 'mode']
@@ -148,13 +169,6 @@ def __init__(self, servers: list,
logprefix: str = ''):
random.shuffle(servers)
self.servers = servers
-
- # for s in servers:
- # if self.check_server(s):
- # self.servers.append(s)
- # print(len(self.servers), len(servers))
- # print(servers)
-
self.current = -1
self.client: Optional[LiteClient] = None
self.timeout = timeout
@@ -549,6 +563,52 @@ def wait_connected(self, timeout: int):
"""Wait until connected with timeout, throw error if not connected"""
return self.client.wait_connected(datetime.datetime.now().timestamp() + timeout)
+ def run_get_method(self, account: Address,
+ method: str,
+ stack: Union[Stack, List] = None,
+ mc_seqno: int = None,
+ block: BlockIdExt = None,
+ c7=None,
+ allow_non_success=False,
+ gas_limit=5000000,
+ gas_max=5000000):
+ from tonpy.tvm.c7 import C7
+
+ if stack is None:
+ stack = []
+
+ if mc_seqno is not None:
+ if block:
+ raise ValueError(f"Can't run get_method with block {block} because block {mc_seqno} is provided")
+ block = BlockId(workchain=-1, shard=MASTER_SHARD, seqno=mc_seqno)
+
+ if block is None:
+ block = self.get_masterchain_info_ext().last
+
+ account_state = self.get_account_state(account, block).get_parsed()
+
+ code = account_state.storage.state.x.code.value
+ data = account_state.storage.state.x.data.value
+
+ tvm = TVM(data=data, code=code, allow_debug=True)
+ tvm.set_gas_limit(gas_limit, gas_max)
+
+ if c7 is None:
+ config = self.get_config_all(block)
+
+ # Todo: last_mc_blocks, prev_key_block, income_extra
+ tvm.set_c7(C7(
+ time=datetime.datetime.now(),
+ balance_grams=account_state.storage.balance.grams.amount.value,
+ address=account,
+ my_code=code,
+ global_config=config[1].get_cell()
+ ))
+
+ tvm.set_stack([*stack, method_name_to_id(method)])
+
+ return tvm.run(allow_non_success=True)
+
@staticmethod
def get_one(timeout: int = 1, threads: int = 1) -> "LiteClient":
server = random.choice(servers)
diff --git a/src/tonpy/types/stack.py b/src/tonpy/types/stack.py
index d1cd231..ccdb366 100644
--- a/src/tonpy/types/stack.py
+++ b/src/tonpy/types/stack.py
@@ -2,6 +2,8 @@
from tonpy.libs.python_ton import PyStackEntry, PyStack, make_tuple, deserialize_stack_entry, deserialize_stack, \
PyContinuation
+
+from tonpy.types.address import Address
from tonpy.types import Cell, CellSlice, CellBuilder
from typing import Union, Iterable, List
from enum import Enum
@@ -60,6 +62,8 @@ def __init__(self, value: "None | Cell | CellSlice | int | CellBuilder | list |
self.entry = StackEntry.create_tuple(value).entry
elif isinstance(value, Continuation):
self.entry = PyStackEntry(continuation=value)
+ elif isinstance(value, Address):
+ self.entry = PyStackEntry(cell_slice=value.to_cs().cell_slice)
else:
raise ValueError(f"Type {type(value)} is not supported")