pytoniq


Namepytoniq JSON
Version 0.1.40 PyPI version JSON
download
home_pagehttps://github.com/yungwine/pytoniq
SummaryTON Blockchain SDK
upload_time2024-10-08 07:54:34
maintainerNone
docs_urlNone
authorMaksim Kurbatov
requires_python>=3.9
licenseNone
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pytoniq

[![PyPI version](https://badge.fury.io/py/pytoniq.svg)](https://badge.fury.io/py/pytoniq) 
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pytoniq)](https://pypi.org/project/pytoniq/)
[![Downloads](https://static.pepy.tech/badge/pytoniq)](https://pepy.tech/project/pytoniq)
[![Downloads](https://static.pepy.tech/badge/pytoniq/month)](https://pepy.tech/project/pytoniq)
[![](https://img.shields.io/badge/%F0%9F%92%8E-TON-grey)](https://ton.org)

Pytoniq is a Python SDK for the TON Blockchain. This library extends [pytoniq-core](https://github.com/yungwine/pytoniq-core) with native `LiteClient` and `ADNL`.

If you have any questions join Python - TON [developers chat](https://t.me/pythonnton).

## Documentation
[GitBook](https://yungwine.gitbook.io/pytoniq-doc/)

## Installation

```commandline
pip install pytoniq 
```

## Examples
You can find them in the [examples](examples/) folder.

## LiteClient

### General LiteClient usage examples

#### Client initializing

```python
from pytoniq import LiteClient


async def main():
    client = LiteClient.from_mainnet_config(  # choose mainnet, testnet or custom config dict
        ls_i=0,  # index of liteserver from config
        trust_level=2,  # trust level to liteserver
        timeout=15  # timeout not includes key blocks synchronization as it works in pytonlib
    )

    await client.connect()
    
    await client.get_masterchain_info()

    await client.reconnect()  # can reconnect to an exising object if had any errors

    await client.close()
    
    """ or use it with context manager: """
    async with LiteClient.from_mainnet_config(ls_i=0, trust_level=2, timeout=15) as client:
        await client.get_masterchain_info()

```

#### Blocks transactions scanning

See `BlockScanner` code [here](examples/blocks/block_scanner.py).

```python
from pytoniq_core import BlockIdExt
from pytoniq import LiteClient
from examples.blocks.block_scanner import BlockScanner  # this import is not available if downloaded from pypi

async def handle_block(block: BlockIdExt):
    if block.workchain == -1:  # skip masterchain blocks
        return
    print(block)
    transactions = await client.raw_get_block_transactions_ext(block)
    for transaction in transactions:
        print(transaction.in_msg)


client = LiteClient.from_mainnet_config(ls_i=14, trust_level=0, timeout=20)


async def main():

    await client.connect()
    await BlockScanner(client=client, block_handler=handle_block).run()
```

## LiteBalancer

`LiteBalancer` is constantly pinging LiteServers to identify "alive" peers.
When you make a request through `LiteBalancer`, it forwards the request to the "best" peer - 
the "alive" peer with the maximum last masterchain block seqno among all and minimum average response time.

`LiteBalancer` can also retry the request if a `asyncio.TimeoutError` occurs, but this must be explicitly set using the
`LiteBalancer.set_max_retries(retries_num)` method.

```python
client = LiteBalancer.from_mainnet_config(trust_level=1)

await client.start_up()

result = await client.run_get_method(address='EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG', method='seqno', stack=[])

await client.close_all()

""" or use it with context manager: """

async with LiteBalancer.from_mainnet_config(trust_level=1) as client:
    result = await client.run_get_method(address='EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG', method='seqno', stack=[])

```

Moreover, one of the most important features of `LiteBalancer` is that it detects [archival](https://docs.ton.org/participate/run-nodes/archive-node#overview) LiteServers,
so you can do requests only to archival LiteServers providing `True` for argument `only_archive` in **any** method:

```python
# ask for very very old block
blk, _ = await client.lookup_block(-1, -2**63, 100, only_archive=True)  

# ask for old block and run get method for that block:
blk, _ = await client.lookup_block(-1, -2**63, 25000000, only_archive=True)
result = await client.run_get_method(address='EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG', method='seqno',
                                             stack=[], block=blk, only_archive=True)

```


### Blockstore
The library can prove all data it receives from a Liteserver (Learn about trust levels [here](https://yungwine.gitbook.io/pytoniq-doc/liteclient/trust-levels)).
If you want to use `LiteClient` or `LiteBalancer` with the zero trust level, at the first time run library will prove block link from the `init_block` to the last masterchain block.
Last proved blocks will be stored in the `.blockstore` folder. The file data contains `ttl` and `gen_utime` of the last synced key block, its data serialized according to the `BlockIdExt` TL scheme (but in big–endian), last synced masterchain block data. 
Filename is first 88 bytes of data described above with init block hash.

## ADNL

```python
from pytoniq.adnl.adnl import AdnlTransport, Node

adnl = AdnlTransport(timeout=3)

# start adnl receiving server
await adnl.start()

# take peer from public config
peer = Node('172.104.59.125', 14432, "/YDNd+IwRUgL0mq21oC0L3RxrS8gTu0nciSPUrhqR78=", adnl)
await adnl.connect_to_peer(peer)
# or await peer.connect()

await peer.disconnect()

# send pings
await asyncio.sleep(10)

# stop adnl receiving server
await adnl.close()
```

## DHT

```python
import time

from pytoniq.adnl.adnl import AdnlTransport
from pytoniq.adnl.dht import DhtClient, DhtNode


adnl = AdnlTransport(timeout=5)
client = DhtClient.from_mainnet_config(adnl)

await adnl.start()

foundation_adnl_addr = '516618cf6cbe9004f6883e742c9a2e3ca53ed02e3e36f4cef62a98ee1e449174'
resp = await client.find_value(key=DhtClient.get_dht_key_id(bytes.fromhex(foundation_adnl_addr)))
print(resp)
#  {'@type': 'dht.valueFound', 'value': {'key': {'key': {'id': '516618cf6cbe9004f6883e742c9a2e3ca53ed02e3e36f4cef62a98ee1e449174', 'name': b'address', 'idx': 0, '@type': 'dht.key'}, 'id': {'key': '927d3e71e3ce651c3f172134d39163f70e4c792169e39f3d520bfad9388ad4ca', '@type': 'pub.ed25519'}, 'update_rule': {'@type': 'dht.updateRule.signature'}, 'signature': b"g\x08\xf8yo\xed1\xb83\x17\xb9\x10\xb4\x8f\x00\x17]D\xd2\xae\xfa\x87\x9f\xf7\xfa\x192\x971\xee'2\x83\x0fk\x03w\xbb0\xfcU\xc8\x89Zm\x8e\xba\xce \xfc\xde\xf2F\xdb\x0cI*\xe0\xaeN\xef\xc2\x9e\r", '@type': 'dht.keyDescription'}, 'value': {'@type': 'adnl.addressList', 'addrs': [{'@type': 'adnl.address.udp', 'ip': -1537433966, 'port': 3333}], 'version': 1694227845, 'reinit_date': 1694227845, 'priority': 0, 'expire_at': 0}, 'ttl': 1695832194, 'signature': b'z\x8aW\x80k\xceXQ\xff\xb9D{C\x98T\x02e\xef&\xfc\xb6\xde\x80y\xf7\xb4\x92\xae\xd2\xd0\xbakU}3\xfa\xec\x03\xb6v\x98\xb0\xcb\xe8\x05\xb9\xd0\x07o\xb6\xa0)I\x17\xcb\x1a\xc4(Dt\xe6y\x18\x0b', '@type': 'dht.value'}}

key = client.get_dht_key(id_=adnl.client.get_key_id())
ts = int(time.time())
value_data = {
    'addrs': [
        {
            "@type": "adnl.address.udp",
            "ip": 1111111,
            "port": 12000
        }
    ],
    'version': ts,
    'reinit_date': ts,
    'priority': 0,
    'expire_at': 0,
}

value = client.schemas.serialize(client.schemas.get_by_name('adnl.addressList'), value_data)

stored = await client.store_value(  # store our address list in dht as value
    key=key,
    value=value,
    private_key=adnl.client.ed25519_private.encode(),
    ttl=100,
    try_find_after=False
)

print(stored)  # True if value was stored, False otherwise

# disconnect from all peers
await client.close()
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/yungwine/pytoniq",
    "name": "pytoniq",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": null,
    "author": "Maksim Kurbatov",
    "author_email": "cyrbatoff@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/26/a0/4d3f4f8d143dc242e544238389dcb3d539409cac764b8e06c60d8f893558/pytoniq-0.1.40.tar.gz",
    "platform": null,
    "description": "# pytoniq\n\n[![PyPI version](https://badge.fury.io/py/pytoniq.svg)](https://badge.fury.io/py/pytoniq) \n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pytoniq)](https://pypi.org/project/pytoniq/)\n[![Downloads](https://static.pepy.tech/badge/pytoniq)](https://pepy.tech/project/pytoniq)\n[![Downloads](https://static.pepy.tech/badge/pytoniq/month)](https://pepy.tech/project/pytoniq)\n[![](https://img.shields.io/badge/%F0%9F%92%8E-TON-grey)](https://ton.org)\n\nPytoniq is a Python SDK for the TON Blockchain. This library extends [pytoniq-core](https://github.com/yungwine/pytoniq-core) with native `LiteClient` and `ADNL`.\n\nIf you have any questions join Python - TON [developers chat](https://t.me/pythonnton).\n\n## Documentation\n[GitBook](https://yungwine.gitbook.io/pytoniq-doc/)\n\n## Installation\n\n```commandline\npip install pytoniq \n```\n\n## Examples\nYou can find them in the [examples](examples/) folder.\n\n## LiteClient\n\n### General LiteClient usage examples\n\n#### Client initializing\n\n```python\nfrom pytoniq import LiteClient\n\n\nasync def main():\n    client = LiteClient.from_mainnet_config(  # choose mainnet, testnet or custom config dict\n        ls_i=0,  # index of liteserver from config\n        trust_level=2,  # trust level to liteserver\n        timeout=15  # timeout not includes key blocks synchronization as it works in pytonlib\n    )\n\n    await client.connect()\n    \n    await client.get_masterchain_info()\n\n    await client.reconnect()  # can reconnect to an exising object if had any errors\n\n    await client.close()\n    \n    \"\"\" or use it with context manager: \"\"\"\n    async with LiteClient.from_mainnet_config(ls_i=0, trust_level=2, timeout=15) as client:\n        await client.get_masterchain_info()\n\n```\n\n#### Blocks transactions scanning\n\nSee `BlockScanner` code [here](examples/blocks/block_scanner.py).\n\n```python\nfrom pytoniq_core import BlockIdExt\nfrom pytoniq import LiteClient\nfrom examples.blocks.block_scanner import BlockScanner  # this import is not available if downloaded from pypi\n\nasync def handle_block(block: BlockIdExt):\n    if block.workchain == -1:  # skip masterchain blocks\n        return\n    print(block)\n    transactions = await client.raw_get_block_transactions_ext(block)\n    for transaction in transactions:\n        print(transaction.in_msg)\n\n\nclient = LiteClient.from_mainnet_config(ls_i=14, trust_level=0, timeout=20)\n\n\nasync def main():\n\n    await client.connect()\n    await BlockScanner(client=client, block_handler=handle_block).run()\n```\n\n## LiteBalancer\n\n`LiteBalancer` is constantly pinging LiteServers to identify \"alive\" peers.\nWhen you make a request through `LiteBalancer`, it forwards the request to the \"best\" peer - \nthe \"alive\" peer with the maximum last masterchain block seqno among all and minimum average response time.\n\n`LiteBalancer` can also retry the request if a `asyncio.TimeoutError` occurs, but this must be explicitly set using the\n`LiteBalancer.set_max_retries(retries_num)` method.\n\n```python\nclient = LiteBalancer.from_mainnet_config(trust_level=1)\n\nawait client.start_up()\n\nresult = await client.run_get_method(address='EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG', method='seqno', stack=[])\n\nawait client.close_all()\n\n\"\"\" or use it with context manager: \"\"\"\n\nasync with LiteBalancer.from_mainnet_config(trust_level=1) as client:\n    result = await client.run_get_method(address='EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG', method='seqno', stack=[])\n\n```\n\nMoreover, one of the most important features of `LiteBalancer` is that it detects [archival](https://docs.ton.org/participate/run-nodes/archive-node#overview) LiteServers,\nso you can do requests only to archival LiteServers providing `True` for argument `only_archive` in **any** method:\n\n```python\n# ask for very very old block\nblk, _ = await client.lookup_block(-1, -2**63, 100, only_archive=True)  \n\n# ask for old block and run get method for that block:\nblk, _ = await client.lookup_block(-1, -2**63, 25000000, only_archive=True)\nresult = await client.run_get_method(address='EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG', method='seqno',\n                                             stack=[], block=blk, only_archive=True)\n\n```\n\n\n### Blockstore\nThe library can prove all data it receives from a Liteserver (Learn about trust levels [here](https://yungwine.gitbook.io/pytoniq-doc/liteclient/trust-levels)).\nIf you want to use `LiteClient` or `LiteBalancer` with the zero trust level, at the first time run library will prove block link from the `init_block` to the last masterchain block.\nLast proved blocks will be stored in the `.blockstore` folder. The file data contains `ttl` and `gen_utime` of the last synced key block, its data serialized according to the `BlockIdExt` TL scheme (but in big\u2013endian), last synced masterchain block data. \nFilename is first 88 bytes of data described above with init block hash.\n\n## ADNL\n\n```python\nfrom pytoniq.adnl.adnl import AdnlTransport, Node\n\nadnl = AdnlTransport(timeout=3)\n\n# start adnl receiving server\nawait adnl.start()\n\n# take peer from public config\npeer = Node('172.104.59.125', 14432, \"/YDNd+IwRUgL0mq21oC0L3RxrS8gTu0nciSPUrhqR78=\", adnl)\nawait adnl.connect_to_peer(peer)\n# or await peer.connect()\n\nawait peer.disconnect()\n\n# send pings\nawait asyncio.sleep(10)\n\n# stop adnl receiving server\nawait adnl.close()\n```\n\n## DHT\n\n```python\nimport time\n\nfrom pytoniq.adnl.adnl import AdnlTransport\nfrom pytoniq.adnl.dht import DhtClient, DhtNode\n\n\nadnl = AdnlTransport(timeout=5)\nclient = DhtClient.from_mainnet_config(adnl)\n\nawait adnl.start()\n\nfoundation_adnl_addr = '516618cf6cbe9004f6883e742c9a2e3ca53ed02e3e36f4cef62a98ee1e449174'\nresp = await client.find_value(key=DhtClient.get_dht_key_id(bytes.fromhex(foundation_adnl_addr)))\nprint(resp)\n#  {'@type': 'dht.valueFound', 'value': {'key': {'key': {'id': '516618cf6cbe9004f6883e742c9a2e3ca53ed02e3e36f4cef62a98ee1e449174', 'name': b'address', 'idx': 0, '@type': 'dht.key'}, 'id': {'key': '927d3e71e3ce651c3f172134d39163f70e4c792169e39f3d520bfad9388ad4ca', '@type': 'pub.ed25519'}, 'update_rule': {'@type': 'dht.updateRule.signature'}, 'signature': b\"g\\x08\\xf8yo\\xed1\\xb83\\x17\\xb9\\x10\\xb4\\x8f\\x00\\x17]D\\xd2\\xae\\xfa\\x87\\x9f\\xf7\\xfa\\x192\\x971\\xee'2\\x83\\x0fk\\x03w\\xbb0\\xfcU\\xc8\\x89Zm\\x8e\\xba\\xce \\xfc\\xde\\xf2F\\xdb\\x0cI*\\xe0\\xaeN\\xef\\xc2\\x9e\\r\", '@type': 'dht.keyDescription'}, 'value': {'@type': 'adnl.addressList', 'addrs': [{'@type': 'adnl.address.udp', 'ip': -1537433966, 'port': 3333}], 'version': 1694227845, 'reinit_date': 1694227845, 'priority': 0, 'expire_at': 0}, 'ttl': 1695832194, 'signature': b'z\\x8aW\\x80k\\xceXQ\\xff\\xb9D{C\\x98T\\x02e\\xef&\\xfc\\xb6\\xde\\x80y\\xf7\\xb4\\x92\\xae\\xd2\\xd0\\xbakU}3\\xfa\\xec\\x03\\xb6v\\x98\\xb0\\xcb\\xe8\\x05\\xb9\\xd0\\x07o\\xb6\\xa0)I\\x17\\xcb\\x1a\\xc4(Dt\\xe6y\\x18\\x0b', '@type': 'dht.value'}}\n\nkey = client.get_dht_key(id_=adnl.client.get_key_id())\nts = int(time.time())\nvalue_data = {\n    'addrs': [\n        {\n            \"@type\": \"adnl.address.udp\",\n            \"ip\": 1111111,\n            \"port\": 12000\n        }\n    ],\n    'version': ts,\n    'reinit_date': ts,\n    'priority': 0,\n    'expire_at': 0,\n}\n\nvalue = client.schemas.serialize(client.schemas.get_by_name('adnl.addressList'), value_data)\n\nstored = await client.store_value(  # store our address list in dht as value\n    key=key,\n    value=value,\n    private_key=adnl.client.ed25519_private.encode(),\n    ttl=100,\n    try_find_after=False\n)\n\nprint(stored)  # True if value was stored, False otherwise\n\n# disconnect from all peers\nawait client.close()\n```\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "TON Blockchain SDK",
    "version": "0.1.40",
    "project_urls": {
        "Homepage": "https://github.com/yungwine/pytoniq"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "be7259e05c74c03772a579c4c491a9d8353d28c3fda80ac05ba6805a9e1d8129",
                "md5": "f563ae6b5164207afe3a3f521898ca8d",
                "sha256": "5d10927abd199937094ed76a7f586d670f04c12138ee28fe149295987240f58b"
            },
            "downloads": -1,
            "filename": "pytoniq-0.1.40-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f563ae6b5164207afe3a3f521898ca8d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 47454,
            "upload_time": "2024-10-08T07:54:32",
            "upload_time_iso_8601": "2024-10-08T07:54:32.344100Z",
            "url": "https://files.pythonhosted.org/packages/be/72/59e05c74c03772a579c4c491a9d8353d28c3fda80ac05ba6805a9e1d8129/pytoniq-0.1.40-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "26a04d3f4f8d143dc242e544238389dcb3d539409cac764b8e06c60d8f893558",
                "md5": "f1205fcf71a6ed88d89dca51629dba41",
                "sha256": "c532a82cc990d9c73a2606e26742b98a2b9e0aa39bd34d2cb2353bdb89b8488d"
            },
            "downloads": -1,
            "filename": "pytoniq-0.1.40.tar.gz",
            "has_sig": false,
            "md5_digest": "f1205fcf71a6ed88d89dca51629dba41",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 44071,
            "upload_time": "2024-10-08T07:54:34",
            "upload_time_iso_8601": "2024-10-08T07:54:34.445043Z",
            "url": "https://files.pythonhosted.org/packages/26/a0/4d3f4f8d143dc242e544238389dcb3d539409cac764b8e06c60d8f893558/pytoniq-0.1.40.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-08 07:54:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "yungwine",
    "github_project": "pytoniq",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "pytoniq"
}
        
Elapsed time: 0.33718s