How To Integrate Blockchain In Python Application

Introduction

In this article, you will learn how to integrate Stratis into your Python application using Startis Blockchain Python SDK, pyStratis. It is recommended to go through the following:

  1. What Is Blockchain
  2. Write Your First Smart Contract On Stratis Blockchain
  3. Do You Need A Blockchain

Stratis Platform

Stratis Ltd. is the creator of Stratis Platform, a blockchain technology platform for enterprises to build enterprise-grade blockchain-based solutions using Microsoft’s .NET framework and C# language. Stratis Platform is easy to learn, adapt, and integrate with existing enterprise applications. Stratis offers both public blockchain and private blockchain solutions. Stratis’s product offerings include Distributed Ledger Technology (DLT), Identity Platform, Supply Trust, STO Platform, DiFi, and Smart Contracts written in C# and executed on native .NET CLR makes it appealing to companies that want to build blockchain solutions on Microsoft stack.

Visit here to learn more about Stratis Platform.

Blockchain Full Node

In a distributed network, there are a lot of computers connected. Each computer is called a node. A node is a point of intersection or connection within the network. It can act as both a redistribution point or a communication endpoint. A Blockchain full node is a node on a Blockchain network.

Every block and transaction is downloaded and checked against Blockchain's consensus rules by full nodes. Even if every other node on the network considers a transaction or block is acceptable, it is rejected if it defies the consensus rules. Miners have limited power on full nodes: they can only rearrange or delete transactions, and only with a lot of computational power. Although a powerful miner may carry out certain major assaults, full nodes rely on miners for just a few things, therefore miners cannot fully modify or destroy the Blockchain.

To know about Stratis Full Node, visit here.

pyStratis

pyStratis enables Python Developers to begin utilizing Stratis Blockchain Technologies in a programming language they are already familiar with. Python is renowned as one of the most widely used programming languages globally. With the development of Python SDK, enthused developers can now begin to leverage Stratis Blockchain Technologies with ease.

Building and signing transactions, dealing with Smart Contracts and getting a blockchain state are all simple tasks that pyStratis can handle. The STRAX Blockchain as well as the Cirrus Sidechain are also fully supported. InterFlux Hub functionality has also been added to allow transactions between Stratis and other blockchains, such as Ethereum.

You can visit pyStratis GitHub to learn more.

ReadTheDocs API documentation can be found at http://pystratis.readthedocs.io.

How to install pyStratis

1. From the Python Package Index (PyPi)

pip install pystratis

2. Most recent (from GitHub)

pip install git+https://github.com/stratisproject/pystratis.git

3. Install from PyPi with test dependencies

pip install pystratis[test]

pyStratis provides a python interface to a running Strax or Cirrus node's API. Therefore, to use pyStratis, you will need a running node daemon.

Strax Core

Strax is the main chain of the Stratis Blockchain. Stratis Core has been updated to fully support transfers to the Cirrus Sidechain, as well as incorporating the latest release of the Stratis Full Node.

The most up-to-date version of the Strax Wallet can be found at https://github.com/stratisproject/StraxUI/releases/.Clone the repository from GitHub, check out the latest release, and enter the directory.

git clone https://github.com/stratisproject/StratisFullNode.git
git checkout -b release/1.0.9.1
cd StratisFullNode\src\Stratis.StraxD

The node daemon can be started with dotnet run.

  • Configuration settings can be updated in the stratis.conf file in the data directory or through command line args.
  • Important (optional) args:
    • -txindex=1 For retrieving individual transaction details. Needed for some API calls.
    • -addressindex=1 For retrieving balance details for individual addresses. Needed for some API calls.
    • -apiuri=0.0.0.0 If node is being run on a remote device on your network (i.e. headless RPi) to access API outside of ssh tunnel.
    • -datadir=<custom datadir path> Change your node's data directory.
    • -testnet Connect the node to the testnet blockchain.
    • -regtest Regression testing network.
    • -port=12344 Change the default connection port.
    • -apiport=12345 Change the api port.
    • -rpcport=12346 Change the rpc port (if active, inactive by default).
    • -signalrport=12347 Change the signalrport.
    • Other arguments can be discovered in the stratis.conf file or by running the dotnet run help command.

We use the following code to initialize Strax Node

from pystratis.nodes import StraxNode
node = StraxNode()

Visit StraxNode to learn more.

Cirrus Core

Cirrus is the sidechain of the Stratis Blockchain. Cirrus tokens are pegged 1:1 with Strax. Cirrus Core wallet, allowing users to create and manage a wallet, interact with Smart Contracts, deploy Smart Contracts and perform cross-chain transfers back to the Stratis Mainchain.

The most up-to-date version of the Cirrus Wallet can be found at https://github.com/stratisproject/CirrusCore/releases/..

Clone the repository from GitHub, check out the latest release, and enter the directory.

git clone https://github.com/stratisproject/StratisFullNode.git
git checkout -b release/1.0.9.1
cd StratisFullNode\src\Stratis.CirrusD

The node daemon can be started with dotnet run.

We use the following code to initialize Cirrus Node

from pystratis.nodes import CirrusNode
node = CirrusNode()

Visit CirrusNode to learn more.

Interflux Gateway (Multisig Masternodes)

  • InterfluxStraxNode - The Strax member of the multisig Interflux Gateway pair.
  • InterfluxCirrusNode - The Cirrus member of the multisig Interflux Gateway pair.
    from pystratis.nodes import InterfluxStraxNode, InterfluxCirrusNode
    strax_node = InterfluxStraxNode()
    cirrus_node = InterfluxCirrusNode()
    

Standard Masternodes

  • StraxMasterNode - The Strax member of the standard masternode pair.
  • CirrusMasterNode - The Cirrus member of the standard masternode pair.
    from pystratis.nodes import StraxMasterNode, CirrusMasterNode
    strax_node = StraxMasterNode()
    cirrus_node = CirrusMasterNode()
    

Node API endpoints

The following are the responsibilities and functions of an Endpoint Node.

  1. Data on the blockchain should be synchronized
  2. Validate the newly received blocks
  3. Responds to query requests
  4. Transaction requests are sent to the Proxy Nodes

At this point, you should have:

  • A running node daemon.
  • An initialized pystratis.node instance.

Active API routes are implemented as class properties.

API endpoints can be called as in the following example:

# API endpoint: http://localhost:17103/api/node/status
from pystratis.nodes import StraxNode
strax_node = StraxNode()
strax_node.node.status()

Please see the pystratis.api namespace documentation for more information on calling specific API endpoints.

pyStratis Encryption Keys

Blockchain technology uses cryptographic hashing algorithms to implement data immutability. That means, once data is written on a blockchain database, no one can modify or change it. Previous hash and consensus mechanisms make tampering with a block’s data very hard.

Blockchain technology uses cryptography to encrypt any sensitive data. Users on the system are anonymous and it uses private and public key combinations in data authentication.

To read more about Cryptography, visit

pystratis.core provides basic key functionality common among cryptocurrency platforms.

The function used in cryptography examples

  • Key() is used to apply the hash function on the given data
  • get_bytes() converts the given hexadecimal string into binary string
  • wif_key() converts the given data into Wallet Import Format(WIF). WIF also known as a Wallet Export Format is a method of encoding a private ECDSA key to make it easier to copy.
  • ExtKey() is used to generate the extended private key
  • ExtPubKey() is used to generate the extended public key
  • generate_private_key_bytes() is used to get private key from this extended private key
  • generate_chain_code_bytes() is used to get chain code from this extended private key.
  • PubKey() is used to generate a compressed public key
  • uncompressed() results in an uncompressed public key

You can read more at pyStratis.Core

In the following way, you can generate and use Private Key

Private key

from pystratis.core import Key

private_key_from_str = Key('5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh')
same_private_key_from_bytes = Key(private_key_from_str.get_bytes())

assert private_key_from_str == same_private_key_from_bytes
assert private_key_from_str.generate_wif_key() == same_private_key_from_bytes.generate_wif_key()
assert str(private_key_from_str) == str(same_private_key_from_bytes)

Extended private key

An extended private key is the combination of a private key and chain code and can be used to derive child private keys (and from them, child public keys)

from pystratis.core import ExtKey

extended_private_key = ExtKey('4Qzpnt5o8msy6thbuFEHTr4yFqp8yvywYBhrtHLJNKEHDhidjbCVvdjuXA2V9k6Bg39FJjfbqpasUmnNYBfZZY27')
another_extended_private_key = ExtKey(extended_private_key.get_bytes())

assert extended_private_key.generate_private_key_bytes() == another_extended_private_key.generate_private_key_bytes()
assert extended_private_key.generate_chain_code_bytes() == another_extended_private_key.generate_chain_code_bytes()

In the following way, you can generate and use Public Key

Public key

from pystratis.core import PubKey

pubkey_compressed = PubKey('034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa')
pubkey_uncompressed = PubKey(pubkey_compressed.uncompressed())

assert pubkey_compressed.x == pubkey_uncompressed.x
assert pubkey_compressed.y == pubkey_uncompressed.y

Extended public key

An extended public key is a public key and chain code, which can be used to create child public keys.

from pystratis.core import ExtPubKey

extended_public_key = ExtPubKey("6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7f
e5JnJ7dh8zL4fiyLHV")
another_extended_public_key = ExtPubKey(str(extended_public_key))

assert extended_public_key == another_extended_public_key

pystratis.core.types

C# integer representations do not exist in Python. pystratis.core.types define several types to facilitate compatibility with the C# StratisFullNode while ensuring overflow protection.

pystratis.core.types include:

  • int32, uint32
  • int64, uint64
  • uint128, uint160, uint256

Money

  • Money is represented in pystratis as a custom type and stored under the hood as a decimal. Decimal value in Coin units.
  • The class method Money.from_satoshi_units() handles conversion from satoshi units to Coin units.
  • The instance method to_coin_unit() represents Money as a string with 8 decimal places.

Address

Misspelling an address is a common cause of lost funds across cryptocurrency networks. The Address type was created to prevent this error by validating the string representation of the address using the provided network. ddress can validate p2pkh, p2sh, p2wpkh, and p2wsh addresses on Strax and Cirrus networks.

Networks supported:

  • StraxMain, StraxTest, StraxRegTest
  • CirrusMain, CirrusTest, CirrusRegTest
  • Ethereum.

hexstr

The hexstr type is a string subclass that restricts inputs to the 0123456789abcdef hexadecimal charset.

Using Strax Wallet through pyStratis

A cryptocurrency wallet is a hardware device, software application, or service that keeps the public and/or private keys for cryptocurrency transactions. A cryptocurrency wallet usually includes the ability to encrypt and/or sign information in addition to the fundamental function of holding keys. Signing can result in the execution of a smart contract, a cryptocurrency transaction, identification, or the legally signing of a "document". Learn more here

To be able to run a wallet, you need to have Stratis FullNode running on your machine. You can learn more about FullNode here.

Creating a wallet

from pystratis.nodes import StraxNode
from typing import List

node = StraxNode()
# Returns the mnemonic representing the HD wallet seed.
mnemonic: List[str] = node.wallet.create(name='ExampleWallet', password='abc123')

Loading a wallet

# Loads a known wallet from the data dir with the given name and decrypts the wallet.
node.wallet.load(name='ExampleWallet', password='abc123')

Recovering a wallet

node.wallet.recover(mnemonic=mnemonic, password='abc123', name='RecoveredWallet')

Listing wallets

wallets: dict = node.wallet.list_wallets()

Creating an account

account_name = node.wallet.account(wallet_name='ExampleWallet', password='abc123')

Listing wallet accounts

node.wallet.accounts(wallet_name='ExampleWallet')

Getting an unused address

unused_address = node.wallet.unused_address(wallet_name='ExampleWallet')

Getting all addresses

addresses = node.wallet.addresses(wallet_name='ExampleWallet')

Getting general information about a wallet

node.wallet.general_info(name='ExampleWallet')

Getting a wallet history

history = node.wallet.history(wallet_name='ExampleWallet')

Resyncing wallet

node.wallet.remove_transactions(
    wallet_name='ExampleWallet',
    remove_all=True, 
    resync=True
)

Getting the balance of a wallet

wallet_balance = node.wallet.balance(
    wallet_name='ExampleWallet', 
    include_balance_by_address=False
)

To learn more about using Strax wallet through pyStratis, visit here.

Signing and verifying a message

signature = node.wallet.sign_message(
  wallet_name='ExampleWallet', 
  password='abc123', 
  external_address=unused_address,
  message='Blockchain made easy.'
)
assert node.wallet.verify_message(
  signature=signature,
  external_address=unused_address,
  message='Blockchain made easy.'
)

Retrieving spendable utxo

The spendable_transactions method returns a SpendableTransactionsModel, which contains a list of SpendableTransactionModel.

from pystratis.nodes import StraxNode
from pystratis.api.wallet.responsemodels import SpendableTransactionsModel
node = StraxNode()
s_txs: SpendableTransactionsModel = node.wallet.spendable_transactions(wallet_name='ExampleWallet')

# Re-order the spendable transactions smallest to largest to preferentially use low value utxos.
s_txs = [x for x in s_txs.transactions]
s_txs = sorted(s_txs, key=lambda x: x.amount)

Building and signing a transaction

Building a transaction means creating a block on the blockchain, and signing a transaction means adding the newly created block as a new node after validating.

The following code shows how we can send a transaction to an unused address on our node.

from pystratis.core import Outpoint, Recipient
from pystratis.core.types import Money
# First we want to define the destination address.
destination_address = node.wallet.unused_address(wallet_name='ExampleWallet')
# The change address is optional. In this case, we are sending any change back to an adress that has a balance.
change_address = node.wallet.balance(
    wallet_name='ExampleWallet', include_balance_by_address=True
).balances[0].addresses[0].address

# Here we are setting a fee (rather than using the fee estimation API call).
fee_amount = Money(0.0001)
amount_to_send = Money(1)

# After declaring the amount being sent, we need to include enough utxos as transaction 
# inputs such that the sum of the input amounts >= the amount being sent.
# The for loop below is one way to accomplish this. 
transactions = []
trxid_amount = Money(0)
for spendable_transaction in s_txs:
    transactions.append(spendable_transaction)
    trxid_amount += spendable_transaction.amount
    if trxid_amount >= amount_to_send: # Can add fee here if not subtracting from amount below.
        break

# The last elements of the transaction to build are the outpoints and the recipients.
# The outpoints are built from the utxos in the previous step. The list comprehension below does this efficiently.
# The recipient list can be 1 or more recipient, but the sum must be less than the amount contained in included utxos.
response = node.wallet.build_transaction(
    fee_amount=fee_amount,
    password='abc123',
    segwit_change_address=False,
    wallet_name='ExampleWallet',
    account_name='account 0',
    outpoints=[Outpoint(transaction_id=x.transaction_id, index=x.index) for x in transactions],
    recipients=[Recipient(destination_address=destination_address, subtraction_fee_from_amount=True, amount=amount_to_send)],
    allow_unconfirmed=False,
    shuffle_outputs=True,
    change_address=change_address
)

# Broadcast the successfully built transaction
response = node.wallet.send_transaction(transaction_hex=response.hex)

Offline signing

The technique of maintaining private keys on an offline device (not connected to the internet) and signing on individual transactions are referred to as "offline transactions." The signature is then copied and pasted onto another connected device before being broadcast into the Bitcoin network.

Offline signing is used mainly to prevent any unauthorized access to the network, which may hamper the network.

Using the same s_txs, amount_to_send, destination_address, and change_address as the last example, we are going to build a transaction that can be signed offline.

response = node.wallet.build_offline_sign_request(
        fee_amount=fee_amount,
        wallet_name='Test',
        account_name='account 0',
        outpoints=[Outpoint(transaction_id=x.transaction_id, index=x.index) for x in transactions],
        recipients=[Recipient(destination_address=destination_address, subtraction_fee_from_amount=True, amount=amount_to_send)],
        allow_unconfirmed=False,
        shuffle_outputs=True,
        change_address=change_address
    )

Once the offline sign request is built, you'll need to do the next step on your offline device. We'll use pydantic it to help move our data to the offline device for signing.

First, you'll need to serialize the response from the API request.

serialized_response = response.json()

# Write the serialized data to a file that can be moved over to the offline device with a thumbdrive.
offline_sign_file = 'offline_sign_model_file'
with open(offline_sign_file, 'w') as f:
    f.write(serialized_response)

The next steps assume you are on the offline device (this should be done with swagger or the UI, but including here for completeness, so that you can understand the complete process).

from pystratis.nodes import StraxNode
from pystratis.api.wallet.responsemodels import BuildOfflineSignModel
import json
offline_node = StraxNode()
with open('offline_sign_model_file', 'r') as f:
    data = json.load(f)
    # Restore the json in to a BuildOfflineSignModel
    offline_sign_model = BuildOfflineSignModel(**data)

response = offline_node.wallet.offline_sign_request(
        wallet_password='password',
        wallet_name='Test',
        wallet_account='account 0',
        unsigned_transaction=offline_sign_model.unsigned_transaction,
        fee=offline_sign_model.fee,
        utxos=offline_sign_model.utxos,
        addresses=offline_sign_model.addresses
    )

# The response of the offline_sign_request is a BuildTransactionModel. 
# We are going to save the hex for importing back to the online computer for broadcasting.
signed_transaction_file = 'signed_transaction_file'
with open(signed_transaction_file, 'w') as f:
    f.write(response.hex)

Back on the online node, time to broadcast the transaction.

from pystratis.core.types import hexstr
with open('signed_transaction_file') as f:
    offline_transaction_hex = hexstr(f.readline())

# Broadcast the successfully built offline transaction
response = node.wallet.send_transaction(transaction_hex=offline_transaction_hex)

Deploying a Smart Contract with pyStratis

A smart contract is a self-executing contract in which the conditions of the buyer-seller agreement are encoded directly into lines of code. The code, as well as the agreements, are disseminated throughout a decentralized blockchain network. Transactions are trackable and irreversible, and the programming regulates their execution. Smart contracts eliminate the requirement for a central authority, legal system, or external enforcement mechanism to carry out trustworthy transactions and agreements between distant, anonymous participants.

This section will demonstrate how to use pystratis to deploy and call a smart contract on the Cirrus network, we will use the CirrusTest testnet. The contract C# code and corresponding bytecode for this example can be found on Github here.

In the following code, I am using a pre-created smart contract, you can learn to create a smart contract here. To dive more and create a voting smart contract, you can visit here.

from pystratis.nodes import CirrusNode
from pystratis.core.networks import CirrusTest
from pystratis.core.types import Money, int32
from pystratis.core import SmartContractParameterType, SmartContractParameter

With the above code, we import the required libraries.

# The smart contracts are available on Cirrus sidechain.
node = CirrusNode(blockchainnetwork=CirrusTest())

contract_code = "4D5A90000300000004000000FFFF0000B8000000000000004000000000000000000000000000000000000000000000000
00000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742
062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C0102005C4BA6F50000000000000
000E00022200B0130000012000000020000000000007231000000200000004000000000001000200000000200000400000
00000000004000000000000000060000000020000000000000300408500001000001000000000100000100000000000001
00000000000000000000000203100004F000000000000000000000000000000000000000000000000000000004000000C0
00000043100001C00000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000200000080000000000000000000000082000004800000000000000000000002E74657874000000781100000020000
00012000000020000000000000000000000000000200000602E72656C6F6300000C0000000040000000020000001400000
00000000000000000000000400000420000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000005431000000000000480000000200050040230000C40D000001000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000001330030084000000000000000203280600000A0202280700000A6F0800000A280300000602042805000006020
52807000006020E042809000006020E05280B000006020E06280D000006020E07280F000006020E082811000006020E092
813000006020E0A2815000006020E0B2817000006020E0C2819000006020E0D281B00000602167201000070281C0000062
62A4602280900000A72290000706F0A00000A2A4A02280900000A7229000070036F0B00000A2A4602280900000A7235000
0706F0C00000A2A4A02280900000A7235000070036F0D00000A2A4E02280900000A72470000706F0E00000A16912A00001
33004001D00000001000011178D0F0000012516039C0A02280900000A7247000070066F0F00000A2A4602280900000A725
90000706F1000000A2A4A02280900000A7259000070036F1100000A2A4602280900000A726B0000706F1200000A2A4A022
80900000A726B000070036F1300000A2A4602280900000A72810000706F1400000A2A4A02280900000A7281000070036F1
500000A2A4602280900000A72970000706F1600000A2A4A02280900000A7297000070036F1700000A2A4602280900000A7
2AB0000706F1800000A2A4A02280900000A72AB000070036F1900000A2A4602280900000A72C10000706F1A00000A2A4A0
2280900000A72C1000070036F1B00000A2A4602280900000A72D50000706F0A00000A2A4A02280900000A72D5000070036
F0B00000A2A4602280900000A72ED0000706F0E00000A2A4A02280900000A72ED000070036F0F00000A2A4602280900000
A72090100706F1C00000A2A4A02280900000A7209010070036F1D00000A2A4602280900000A72210100706F1E00000A2A4
A02280900000A7221010070036F1F00000A2A001330040055000000020000117239010070038C10000001282000000A0A0
2280900000A06046F1300000A021201FE15030000021201037D010000041201047D0200000407280100002B72530100700
602280900000A066F1200000A282200000A2A00000042534A4201000100000000000C00000076342E302E3330333139000
0000005006C00000058050000237E0000C4050000BC04000023537472696E677300000000800A00006801000023555300E
80B0000100000002347554944000000F80B0000CC01000023426C6F6200000000000000020000015715A201090A000000F
A013300160000010000001200000003000000020000001C0000001C000000220000000500000002000000010000000D000
0001A000000010000000200000001000000010000000000F30201000000000006002102AA0306006002AA0306000D02970
30F00CA0300000A0050022D040A004B042D040A00C1012D040A0025042D040A0067012D040A0025012D040600B70138030
A0041022D040A009A012D040A00E8012D0406009C0238030600700038030600DD02380306006F043803000000006F01000
000000100010001001000590400001900010001000A011000E40200002D0001001D0006008304D3000600AF01D60050200
000000086189103D9000100E0200000000086087D031B000E00F2200000000086088703EF000E000521000000008608150
3F5000F0017210000000081082203F9000F002A210000000086087E02FE00100040210000000081088B020201100069210
000000086084F03070111007B210000000081085C030B0111008E21000000008608BB0210011200A021000000008108CA0
214011200B321000000008608150019011300C52100000000810824001D011300D821000000008608500022011400EA210
000000081085E0001001400FD210000000086088A00260115000F2200000000810899002A0115002222000000008608C50
02F0116003422000000008108D30033011600472200000000860801041B00170059220000000081081104EF0017006C220
000000086088904380118007E220000000081089B043D0118009122000000008608430143011900A322000000008108530
148011900B62200000000860801014E011A00C822000000008108110153011A00DC220000000086008F0159011B0000000
100D501000002002F0300000300980200000400690300000500D902000006003300000007006C0000000800A8000000090
0E10000000A00210400000B00AD0400000C00630100000D00210100000100A10200000100A10200000100A10200000100A
10200000100A10200000100A10200000100A10200000100A10200000100A10200000100A10200000100A10200000100A10
200000100A10200000100760400000200AF01090091030100110091030600190091030A002900910306006100910306003
100910310003100A3011600690072031B003100F90120007100EB0325007100F6032B0071000503320071000D033700710
0D9033D007100E203480071003F034F007100470354007100A7025A007100B1025F0071000100650071000B006A0071003
E007000710047007500710076007B007100800080007100B30086007100BC008B0071002D0191007100380197007100EB0
09E007100F600A40089004404B1003100EF02B70089004404C30021002B00C4012E000B0093012E0013009C012E001B00B
B0143002300C4014300AB000200010000008B035F0100002603640100008F026801000060036C010000CE0270010000280
0740100006200780100009D007C010000D7008001000015045F0100009F048401000057018901000015018E01020002000
30001000300030002000400050001000500050002000600070001000700070002000800090001000900090002000A000B0
001000B000B0002000C000D0001000D000D0002000E000F0001000F000F000200100011000100110011000200120013000
1001300130002001400150001001500150002001600170001001700170002001800190001001900190002001A001B00010
01B001B000480000000000000000000000000000000004B040000040000000000000000000000CA0078010000000002000
000000000000000000000002D0400000000030002004300BE0000000047657455496E7433320053657455496E743332006
765745F5465737455496E743332007365745F5465737455496E743332007465737455496E74333200476574496E7433320
0536574496E743332006765745F54657374496E743332007365745F54657374496E7433320074657374496E74333200476
57455496E7436340053657455496E743634006765745F5465737455496E743634007365745F5465737455496E743634007
465737455496E74363400476574496E74363400536574496E743634006765745F54657374496E743634007365745F54657
374496E7436340074657374496E7436340047657455496E743235360053657455496E74323536006765745F54657374554
96E74323536007365745F5465737455496E74323536007465737455496E743235360047657455496E74313238005365745
5496E74313238006765745F5465737455496E74313238007365745F5465737455496E74313238007465737455496E74313
238003C4D6F64756C653E0053797374656D2E507269766174652E436F72654C696200546573744D6574686F6400494D657
373616765006765745F4D657373616765006D6573736167650056616C7565547970650049536D617274436F6E747261637
4537461746500736D617274436F6E74726163745374617465004950657273697374656E745374617465006765745F50657
273697374656E7453746174650044656275676761626C6541747472696275746500436F6D70696C6174696F6E52656C617
86174696F6E7341747472696275746500496E646578417474726962757465004465706C6F7941747472696275746500527
56E74696D65436F6D7061746962696C697479417474726962757465006765745F5465737442797465007365745F5465737
4427974650074657374427974650076616C756500476574537472696E6700536574537472696E67006765745F546573745
37472696E67007365745F54657374537472696E670074657374537472696E6700546573744D6573736167654C6F6700536
D617274436F6E74726163742E646C6C00476574426F6F6C00536574426F6F6C006765745F54657374426F6F6C007365745
F54657374426F6F6C0074657374426F6F6C0053797374656D00476574436861720053657443686172006765745F5465737
443686172007365745F5465737443686172007465737443686172006765745F53656E646572006765745F4F776E6572007
365745F4F776E6572002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652
E436F6D70696C6572536572766963657300446562756767696E674D6F64657300476574427974657300536574427974657
300476574416464726573730053657441646472657373006765745F5465737441646472657373007365745F54657374416
4647265737300746573744164647265737300537472617469732E536D617274436F6E74726163747300466F726D6174005
36D617274436F6E74726163740043697272757341504954657374436F6E7472616374004F626A656374006D65737361676
5496E64657800696E646578006765745F54657374427974654172726179007365745F54657374427974654172726179007
46573744279746541727261790000002743006F006E0074007200610063007400200069006E00690074006900610074006
50064002E00000B4F0077006E00650072000011540065007300740042006F006F006C00001154006500730074004200790
0740065000011540065007300740043006800610072000015540065007300740053007400720069006E006700001554006
50073007400550049006E007400330032000013540065007300740049006E0074003300320000155400650073007400550
049006E007400360034000013540065007300740049006E007400360034000017540065007300740041006400640072006
50073007300001B540065007300740042007900740065004100720072006100790000175400650073007400550049006E0
0740031003200380000175400650073007400550049006E00740032003500360000194D006500730073006100670065005
B007B0030007D005D0000117B0030007D003A0020007B0031007D00000000003EF8487F7FA70F43BFB52ADCC4057E2D000
4200101080320000105200101111105200101121D04200012350420001121042000123905200111210E062002010E11210
42001020E052002010E020520011D050E0407011D05062002010E1D05042001030E052002010E030420010E0E052002010
E0E042001090E052002010E09042001080E052002010E080420010B0E052002010E0B0420010A0E052002010E0A0520011
1250E062002010E112505200111290E062002010E11290507020E110C0500020E0E1C06300101011E00040A01110C06000
30E0E1C1C087CEC85D7BEA7798E02060802060E15200D01121D0205030E09080B0A11211D0511251129052001011121032
0000204200101020320000504200101050320000304200101030320000E042001010E03200009042001010903200008032
0000B042001010B0320000A042001010A0420001D05052001011D050420001125052001011125042000112905200101112
90520020E080E04280011210328000203280005032800030328000E03280009032800080328000B0328000A0428001D050
42800112504280011290801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F77730
10801000200000000000401000000000000000000000000000000000000100000000000000000000000000000004831000
00000000000000000623100000020000000000000000000000000000000000000000000005431000000000000000000000
0005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF2500200010000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000003000000C000000743100000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

# An example address of smart contract sender.
my_address = node.wallet.addresses(wallet_name='mywallet').addresses[0].address

In the above code, we do 3 things. First, we will create an instance of CirrusTest, then assign the contract bytecode, and then set up our wallet.

build_transaction = node.smart_contracts.build_create(
    wallet_name='mywallet',
    password='qwerty12345', 
    fee_amount=Money(0.001), 
    contract_code=contract_code,
    gas_price=100, # recommended value
    gas_limit=50000, # recommended value
    sender=my_address,
    amount=Money(0.1)
)

In the above code, we build a demo transaction. I have used recommended values for both gas price and gas limit. Gas refers to the fee, or pricing value, required to successfully conduct a transaction or execute a contract on the Stratis blockchain platform. You can learn more about Gas Prices, here.

node.smart_contracts.local_call(
    contract_address=build_transaction.new_contract_address, 
    method_name='TestMethod',
    amount=Money(0.1),
    gas_price=100,
    gas_limit=50000,
    sender=my_address,
    parameters=[
        SmartContractParameter(value_type=SmartContractParameterType.Int32, value=int32(0)),
        SmartContractParameter(value_type=SmartContractParameterType.String, value='SmartContracts made easy.'),
    ]
)

In the above code, before deploying the smart contract, we need to test it on a local machine. In order to test, we create a local call, to test our contract. We do this by calling "TestMethod", which persists a message string at a specified integer index. Since we are not passing any wallet name, hence we don't have a risk of losing Strax. This is similar to what we do in C# using SCT Tool.

From Stratis documentation,

“A contract call uses a regular transaction that is broadcast to the network. The call parameters are encapsulated in the transaction and handled by the network in the same way as any other transaction. Every node in the network will execute a contract call. If a contract call modifies the state database, the global state is changed.

A local call does not require a transaction. Instead, it passes the call data directly to the local node and executes it on the local machine only. A local call runs against a copy of the state database. If the local call makes changes to the state, these changes are discarded after execution.

Local calls can be used to read the contract state without expending gas (to query the value of a property for example). A local call can also aid in estimating gas costs without needing to broadcast transactions to the main network.”

Once we are certain about the performance of the contract, we are all set to deploy it on the test net or main net, whichever suits you. Since we will be deploying, hence we are not required to make a local call.

node.smart_contract_wallet.send_transaction(build_transaction.hex)

# Now we can call any methods of the deployed smart contract.
node.smart_contract_wallet.call(
    wallet_name='mywallet', 
    password='qwerty12345', 
    contract_address=build_transaction.new_contract_address,
    method_name='TestMethod',
    fee_amount=Money(0.001), 
    gas_price=100,
    gas_limit=50000,
    sender=my_address,
    amount=Money(0.1),
    parameters=[
        SmartContractParameter(value_type=SmartContractParameterType.Int32, value=int32(0)),
        SmartContractParameter(value_type=SmartContractParameterType.String, value='SmartContracts made easy.'),
    ]
)

We use node.smart_contract_wallet.create() to create and deploy the smart contract.

In the above code, we make a call, and this time we pass the wallet details, unlike a local call, this call will cost us Strax.

To learn more about the methods used in this section, visit Smart Contacts and Smart Contract Wallet.

Conclusion

So, we have reached the end of the article, in this article we discussed pyStratis, how to install pyStratis, using Strax Core and Cirrus Core Nodes, Stratis Node API endpoints, how to encrypt and decrypt, how to set up and use Stratis wallet, building and signing a transaction, offline signing, and how to deploy a smart contract, all using pyStratis.

For any doubts or clarification, feel free to visit Stratis Discord. To read more content visit C# Corner's Stratis Blockchain category.

Visit C# Corner to find answers to more such questions.

If you have any questions regarding any other technology do have a look at the C# Corner Technology Page.