Welcome to the PyLibSIMBA walkthrough

We will go through the simple steps it takes to submit a message to a blockchain, and verify the message arrived.

First lets import PyLibSIMBA

This is already installed in the notebook so we can do

In [ ]:
import pylibsimba

Test 1 - Generate a Wallet

This holds the public and private keys used to sign a transaction, and creates an address to send the transactions from.

We will import a helper class and generate a wallet.

Advanced usage:

If you create a contract on simbachain.com which uses a blockchain which requires currency, ensure that a wallet with that address has the correct balance (via their website, spigot etc), and initialise the Wallet object above with the mnemonic associated with that wallet. The Wallet object will then have the same address and can be used to sign transactions on that blockchain.

In [ ]:
from pylibsimba.wallet import Wallet

Now we can generate a wallet to use on the SIMBAChain test blockchain.

In [ ]:
wallet = Wallet(None)
wallet.generate_wallet()
addr = wallet.get_address()
print(addr)

Test 2 - Get the SIMBAChain object.

For the this step we need to import a few things.

Specifically we need the ability to get a SIMBAChain object.

Most of the outputs are in JSON format, so we import that too.

In [ ]:
from pylibsimba import get_simba_instance
import json

Now we can get a SIMBAChain instance, which is used for all interactions with the SIMBAChain API.

This requires a few parameters:

  • url : The API URL
    • We'll use the test endpoint from simbachain.com
  • wallet : The Wallet to use
    • This is the wallet we just made above
  • api_key : (Optional) The API key
    • This is a test API pre generated for this example.
    • Please register at simbachain.com to gain the ability to create your own contracts and access them via you own API key.
  • management_key : (Optional) The Management API key
    • As for the api_key, but unused for now.
In [ ]:
simba = get_simba_instance(
    'https://api.simbachain.com/v1/libSimba-SimbaChat-Quorum/',
    wallet,
    '04d1729f7144873851a745d2ae85639f55c8e3de5aea626a2bcd0055c01ba6fc',
    '')

Using the SIMBAChain instance

Lets check the balance of our wallet. To do this we simply get_balance() from the simba instance we've just created.

The output is a dict, so we'll use json to dump it to a string.

In [ ]:
balance = simba.get_balance()
print("Balance: {}".format(json.dumps(balance, indent=4)))

The output shows the balance as -1, but we can also see that "poa": true meaning this is a Proof of Authority blockchain, so no currency is required.

Test 3 - Calling a method on a Smart Contract via SIMBAChain.com

First, we need the parameters to call the method with.

As it's an example method, the params are given below. (We'll look at how to get the paramters for a different method later)

In [ ]:
method_params = {
    'assetId': "0xbad65ff688a28efdd17d979c12f0ab2e2de305dbc8a2aa6be45ed644da822cfb",
    'name': "A Test Room",
    'createdBy': "PyLibSIMBA",
}

Call the method with the parameters. That's it!

In [ ]:
resp = simba.call_method('createRoom', method_params)
print("Successful submitting? {}".format(resp.transaction_id))

Did it work?

There is a delay between submitting a transaction, and it appearing on the blockchain.

We have the option to "send and forget", or check to see if it has "deployed" successfully.

To be completely sure, we can run wait_for_success_or_error() to check.

Be aware this can take some time, and a variety of errors can be thrown if a problem is detected. Please check the documentation on Exceptions to learn about the types of errors caught by the PyLibSIMBA SDK.

In [ ]:
try:
    final_resp = simba.wait_for_success_or_error(resp.transaction_id)
    print("Successful? {}".format(final_resp))

except Exception as e1:
    print("Failure! {}".format(e1))

Test 4 - Calling a method and submitting files

Similar to above, we need some method parameters, and we'll add some files too.

In [ ]:
method_params = {
    'assetId': "A Test Room",
    'chatRoom': "A Test Room",
    'message': "Hello World",
    'sentBy': "PyLibSIMBA"
}

files = {
    "test file 1.txt": open("test_files/test file 1.txt", 'rb'),
    "test file 2.txt": open("test_files/test file 2.txt", 'rb')
}

Instead of call_method() we use call_method_with_file()

To be sure it worked, we'll add a wait again. This operation will take several seconds to complete.

N.B, Ensure the files exist in the given location, or the method will return an error.

In [ ]:
try:
    resp = simba.call_method_with_file('sendMessage', method_params, files)
    print("Successful submitting? {}".format(resp.transaction_id))

    resp = simba.wait_for_success_or_error(resp.transaction_id)
    print("Successfully deployed? {}".format(resp))
except Exception as e1:
    print("Something went wrong: {}".format(e1))
In [ ]:
!ls ../tests

Test 5 - A list of transactions for the method "createRoom"

We can get a list of all transactions for the method "createRoom".

The result is a PagedResponse class, which holds information about the number of results and a way to 'page' through them.

We can also filter so we only see the transactions that we have created, using createdBy_exact.

The output from this can be extensive and very detailed, so we'll use json.dumps() to "pretty print" it.

In [ ]:
method_params = {
    'createdBy_exact': "PyLibSIMBA"
}
result_pages = simba.get_method_transactions('createRoom', method_params)

print("Number of results for transaction {}: {}".format('createRoom', result_pages.count()))

print("Got data : \n{}".format(
    json.dumps(
        result_pages.data(), indent=4
    )
))

Test 6 - Get an existing example transaction object by the transaction ID.

Use the example transaction ID given, or one from previous called methods above.

In [ ]:
transaction_id = "97b56a4dd3ff4fe7820f46a7101f72e2"
txn = simba.get_transaction(transaction_id)

print("Transaction : \n{}".format(
    json.dumps(txn, indent=4)
))

Test 7 - Get the Transaction Metadata object for an existing example, by the transaction hash.

In [ ]:
transaction_hash = "0x7565461be84259d5e365c2c3225696a6d74245f1eca1ecc050b1fedd5a4a1f4d"
txn_metadata = simba.get_bundle_metadata_for_transaction(transaction_hash)
print("Transaction Metadata: \n{}".format(json.dumps(txn_metadata, indent=4)))

Test 8 - Get a bundle of files from a given transaction, from the transaction hash

Writes the bundle to "the_bundle.zip".

This implementation sets stream=True so that the requests module doesn't download the whole bundle into memory first.

We can also check for errors with raise_for_status()

In [ ]:
transaction_hash = "0x7565461be84259d5e365c2c3225696a6d74245f1eca1ecc050b1fedd5a4a1f4d"
req = simba.get_bundle_for_transaction(transaction_hash, stream=True)
req.raise_for_status()

Writing the "bundle" file to disk

The bundle of files is actually a zip file with all of the files submitted in the transaction, along with some metadata used to check their validity.

Writing the file is done as usual with the python requests package.

To check the file was written to disk, we do a isfile() check

In [ ]:
output_file = 'the_bundle.zip'
with open('the_bundle.zip', 'wb') as f:
    for chunk in req.iter_content(chunk_size=8192):
        if chunk:  # filter out keep-alive new chunks
            f.write(chunk)

import os      
print("Wrote file {}: {}".format(
    output_file,
    os.path.isfile(os.path.abspath(output_file)))
)

Test 9 - Get the first file from a bundle for a given transaction, from the transaction hash

Writes the file to "file_0.txt"

Very similar to the example above, but specifying an index from the list of files submitted in the transaction.

In [ ]:
transaction_hash = "0x7565461be84259d5e365c2c3225696a6d74245f1eca1ecc050b1fedd5a4a1f4d"

req = simba.get_file_from_bundle_for_transaction(transaction_hash, 0, stream=True)
req.raise_for_status()

output_file = 'file_0.txt'
with open(output_file, 'wb') as f:
    for chunk in req.iter_content(chunk_size=8192):
        if chunk:  # filter out keep-alive new chunks
            f.write(chunk)
            
print("Wrote file {}: {}".format(
    output_file,
    os.path.isfile(os.path.abspath(output_file)))
)

Test 10 - Get a file by name, from a bundle for a given transaction, from the transaction hash

Again, as above, but getting the file by name.

Writes the file to "File1.txt"

In [ ]:
transaction_hash = "0x7565461be84259d5e365c2c3225696a6d74245f1eca1ecc050b1fedd5a4a1f4d"

filename = "File1.txt"
req = simba.get_file_from_bundle_by_name_for_transaction(transaction_hash, filename, stream=True)
req.raise_for_status()

output_file = 'File1.txt'
with open(output_file, 'wb') as f:
    for chunk in req.iter_content(chunk_size=8192):
        if chunk:  # filter out keep-alive new chunks
            f.write(chunk)
            
print("Wrote file \n{}: {}".format(
    output_file,
    os.path.isfile(os.path.abspath(output_file)))
)

Test 12 - Get the organisations this user belongs to

This is useful when performing more low-level API calls.

In [ ]:
paged_response = simba.get_organisations()

for org in paged_response.data():
    print(org['id'])

Test 13 - Push arbitrary solidity code to simbachain.com

The create_contract() method takes four parameters:

  • The simba object
  • The path to a file containing the solidity code
  • The name to call the Smart Contract. This will be shown in the dashboard.
  • An organisation id. A user can be a member of multiple organisations, so this is the organisation the Smart Contract will be associated with.

A contract name must be unique within an organisation, so we will add a timestamp to the name so this test organisation will accept it.

In [ ]:
from _datetime import datetime
from pylibsimba import util

response = util.create_contract(
    simba,
    '../tests/example.sol',
    'example_contract_{}'.format(datetime.now().isoformat()),
    '5cd5cef4cabb4b009e00b6b3ff45ee08'
)
print("Wrote contract : \n{}".format(
    json.dumps(response.json(), indent=4)
))

Get in touch!

If you have any issues with the demo above, please let us know via the GitHub issues pages, https://github.com/SIMBAChain/PyLibSIMBA/issues