Skip to content
🐍 Python utils for tezos: keys, signatures, rpc
Branch: master
Clone or download
Pull request Compare This branch is 67 commits ahead, 2 commits behind murbard:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
docs
examples
pytezos refactor Key class Apr 25, 2019
tests
.gitignore
.travis.yml
LICENSE.md
README.md
mkdocs.yml
poetry.lock
pyproject.toml

README.md

PyTezos

Build Status Made With License: MIT

Python utils for Tezos.

Requirements

  • git
  • python 3.6+ (can't resist string interpolation)
  • pip 19.0.1+ (in order to support poetry packages)

You will also probably need to install several cryptographic packets:

$ sudo apt install libsodium-dev libsecp256k1-dev libgmp-dev

Installation

$ pip install git+https://github.com/murbard/pytezos

Usage

Crypto: keys and signatures

All the three elliptic curves are now supported: ed25519, secp256k1, p256 (secp256r1).

from pytezos.crypto import Key

private_key = 'edsk3nM41ygNfSxVU4w1uAW3G9EnTQEB5rjojeZedLTGmiGRcierVv'

Key(private_key).public_key()
>>> 'edpku976gpuAD2bXyx1XGraeKuCo1gUZ3LAJcHM12W1ecxZwoiu22R'

Key(private_key).public_key_hash()
>>> 'tz1eKkWU5hGtfLUiqNpucHrXymm83z3DG9Sq'

Key(private_key).sign('test')
>>> 'edsigtzLBGCyadERX1QsYHKpwnxSxEYQeGLnJGsSkHEsyY8vB5GcNdnvzUZDdFevJK7YZQ2ujwVjvQZn62ahCEcy74AwtbA8HuN'

public_key = 'edpku976gpuAD2bXyx1XGraeKuCo1gUZ3LAJcHM12W1ecxZwoiu22R'
signature = 'edsigtzLBGCyadERX1QsYHKpwnxSxEYQeGLnJGsSkHEsyY8vB5GcNdnvzUZDdFevJK7YZQ2ujwVjvQZn62ahCEcy74AwtbA8HuN'

Key(public_key).verify(signature, 'fake')
>>> Exception('Signature is not valid.')

RPC: query builder and a little bit more

Tezos node API was designed with REST in mind and this package reflects it as well. Basically it's a query building machine, like sqlalchemy for SQL. In addition to this functional it also offers smart caching, shortcuts, and autocomplete, which is very helpful for doing researches in jupyter notebook for instance.

from pytezos.rpc import mainnet

mainnet.head.hash
>>> chains/main/blocks/head/hash

mainnet.head.hash()
>>> 'BKiWhfLw4Qc49pzimVZkvUW5UKbhcbEDNc8UXsbuLsztu92RG8U'

mainnet.blocks(length=2, head='BLyvi5G4i6zaqLPL2r1k2SLKwQp8tsYXEf4mAVrwRjF9w4qVVSv')
>>> [['BLyvi5G4i6zaqLPL2r1k2SLKwQp8tsYXEf4mAVrwRjF9w4qVVSv',
  'BKiWhfLw4Qc49pzimVZkvUW5UKbhcbEDNc8UXsbuLsztu92RG8U']]

mainnet.head.operations[0, 0]
>>> chains/main/blocks/head/operations/0/0

mainnet.context.contracts['tz1TNWtofRofCU11YwCNwTMWNFBodYi6eNqU']()
>>> {'manager': 'tz1TNWtofRofCU11YwCNwTMWNFBodYi6eNqU',
 'balance': '384854285987',
 'spendable': True,
 'delegate': {'setable': False,
  'value': 'tz1TNWtofRofCU11YwCNwTMWNFBodYi6eNqU'},
 'counter': '2317'}

There are also some syntax sugar for convenient collection iteration:

mainnet.blocks[329830:329836]
>>> [['BLiZM5t1cQSDde9Acv4JGYNetA3rS6tAEinvkwYhaFvMvsQE9XB',
  'BLZ1R83AHKknKzmNPqF22aMYL6jQcPU1EBQ8W1PagV3ag6pysWQ',
  'BLXCMEHUpHtwB1RoFGnzVnoVf7FEmeEwz8Ad5dxtrRcq5tD3DeB',
  'BLVrBJyGdm9j4su7exVtkTNi4aJ1D9ephUfPfZFzZwGoRDc8T5z',
  'BLuNPrD4QxjBWc26eDnuoCg7qFSutVURoZpToHshLbbuhZBsb5X',
  'BKujfxvZvqrVmz4anJz6JNQgKe5w7sudcb7awBKUYY39XhReMQp']]

mainnet.blocks[-2:]
>>> [['BKkAhaDbzaFEm99wWedeELxzXHrozQrG4B4p8BU56ttmDjsMdge',
  'BL8u6Ny9naUnVWAtNJQ4P93LfgW8x9LDUCGoW9TEEzqHiG4mPsu']]

And several methods for operations manipulation:

ops = mainnet.mempool.pending_operations.applied(kind='endorsement')

ops[0].forge()
>>> '6b96a5df309727b4cd9a2aee24a56a83565db00d7dce158d5b55400d92f5022c0000050888'

ops[0].preapply()
>>> [{'contents': [{'kind': 'endorsement',
    'level': 329864,
    'metadata': {'balance_updates': [{'kind': 'contract',
       'contract': 'tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9',
       'change': '-128000000'},
      {'kind': 'freezer',
       'category': 'deposits',
       'delegate': 'tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9',
       'level': 80,
       'change': '128000000'},
      {'kind': 'freezer',
       'category': 'rewards',
       'delegate': 'tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9',
       'level': 80,
       'change': '4000000'}],
     'delegate': 'tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9',
     'slots': [15, 5]}}],
  'signature': 'sigsfBsrxKVcS8btuik6vgqR1TRNundZD36ph2tEgjUQdMqHjrNYziJ6godapYMCKq483XqS7rcvfPD61StZ63TE5Jchujs4'}]

ops[0].verify_signature()
>>> No exceptions

The best thing about this wrapper is that you can use not yet wrapped RPC endpoints:

mainnet.context.delegates(active=True)
>>> ['tz2KuCcKSyMzs8wRJXzjqoHgojPkSUem8ZBS',
 'tz2JMPu9yVKuX2Au8UUbp7YrKBZJSdYhgwwu',
 'tz2E3BvcMiGvFEgNVdsAiwVvPHcwJDTA8wLt', ... ]

Or just use raw requests:

from pytezos.rpc.node import Node

node = Node()
node.get('chains/main/blocks', params={'length': 1})
>>> [['BKvRWnbPeFzFNJ9mkUEcxCzYk68fLa3mPYweqcFVo7TNLAJAz2G'], ... ]

node.post('chains/main/mempool/filter', json={'minimal_fees': 0})
>>> {}
You can’t perform that action at this time.