Getting started with Symbol in Python – part 3

This post is based on the third in a series published articles from @nobu_kyutech and his work on interacting with the Symbol blockchain using Python. You can find his original examples in Japanese on GitHub

THANKS AGAIN @NOBU_KYUTECH!

Obtaining the harvest history of a Symbol address

In today’s post I will cover the third of @nobu_kyutech‘s examples on GitHub which provides a beginners guide to using Python to interact with Symbol API nodes in order to retrieve information.

In the previous article we showed how to write a Python script to retrieve recent XYM transactions sent and received by a Symbol account address. Today we will apply a similar methodology to query the harvesting history of an account address.

In this example we will query a node directly using the API and this time search receipts to identify when an account has harvested and the fees earned for each block. As with the last exercise we will be doing this programmatically in Python and I will provide a Jupyter notebook that you can use. Again I will try to explain @nobu_kyutech‘s code in English and usual caveats apply – I am not a Python programmer, apologies if I make any mistakes! 🙂

Ready? Great! Let’s get stated..

Types of receipt on the Symbol blockchain

We saw in the previous example that Symbol has a multitude of different transaction types. This is also true of receipts. Each of these receipt types has a different “enum” code associated with it. These are shown below and explained in more detail here. The important message is that we can use these codes to retrieve only the receipt types that we are interested in (in our case harvest fee):

 0x124D (4685 decimal) - Mosaic_Rental_Fee.
 0x134E (4942 decimal) - Namespace_Rental_Fee.
 0x2143 (8515 decimal) - Harvest_Fee.
 0x2248 (8776 decimal) - LockHash_Completed.
 0x2348 (9032 decimal) - LockHash_Expired.
 0x2252 (8786 decimal) - LockSecret_Completed.
 0x2352 (9042 decimal) - LockSecret_Expired.
 0x3148 (12616 decimal) - LockHash_Created.
 0x3152 (12626 decimal) - LockSecret_Created.
 0x414D (16717 decimal) - Mosaic_Expired.
 0x414E (16718 decimal) - Namespace_Expired.
 0x424E (16974 decimal) - Namespace_Deleted.
 0x5143 (20803 decimal) - Inflation.
 0xE143 (57667 decimal) - Transaction_Group.
 0xF143 (61763 decimal) - Address_Alias_Resolution.
 0xF243 (62019 decimal) - Mosaic_Alias_Resolution.

Getting started

We first need to start a new Jupyter Notebook and the import urllib.request and json modules.

import urllib.request
import json

Next we need to set which node and account we want to query and specify which receipts we are interested in looking at. We want to retrieve harvesting income so looking at the table above we can see that the decimal identifier for “Harvest_Fee” is 8515 so we set ENUM_Harvest_Fee=8515

# Set the node URL
NODEURL = "http://xymharvesting.net:3000"

# Set the address of the account that we want to query
ADDRESS = "NBMWZZZOCUKZXXHKB7R3P3G2ZCO4CSGIXC37USI"

# Set the enum value of the receipt "Harvest_Fee"
ENUM_Harvest_Fee = 8515

As in the previous exercise we have to get the 48 character hexadecimal address of the account.

# Look up the 48 character hexadecimal format version of ADDRESS
req = urllib.request.Request(NODEURL + '/accounts/' + ADDRESS)
with urllib.request.urlopen(req) as res:
     accountInfo = json.load(res)
ADDRESS48 = accountInfo['account']['address']

If we print ADDRESS48 we see that it returns the value 68596CE72E15159BDCEA0FE3B7ECDAC89DC148C8B8B7FA49

So let’s get transactions for the account in json format:

# Now we can get a list of all statements in descending order (newest first)
# The URL would be http://xymharvesting.net:3000/statements/transaction?targetAddress=NBMWZZZOCUKZXXHKB7R3P3G2ZCO4CSGIXC37USI&order=desc

url = NODEURL + '/statements/transaction'
params = {
    'targetAddress': ADDRESS,
    'order': 'desc',
}
req = urllib.request.Request('{}?{}'.format(url, urllib.parse.urlencode(params)))
with urllib.request.urlopen(req) as res:
    data = json.load(res)
    print(json.dumps(data, indent=2))

This, like in the last example returns a lot of transactions:

{
   "data": [
     {
       "statement": {
         "height": "224753",
         "source": {
           "primaryId": 0,
           "secondaryId": 0
         },
         "receipts": [
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68596CE72E15159BDCEA0FE3B7ECDAC89DC148C8B8B7FA49",
             "mosaicId": "6BED913FA20223F8",
             "amount": "128635166"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68693706B3EA603157D423C4F29ED6701CF70960E831D2AD",
             "mosaicId": "6BED913FA20223F8",
             "amount": "9188226"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "684575A96630EC6C0B9FBF3408007213321AFF07A7837E50",
             "mosaicId": "6BED913FA20223F8",
             "amount": "45941130"
           },
           {
             "version": 1,
             "type": 20803,
             "mosaicId": "6BED913FA20223F8",
             "amount": "183764522"
           }
         ]
       },
       "id": "60B8347CDECE12747874000E"
     },
     {
       "statement": {
         "height": "193175",
         "source": {
           "primaryId": 0,
           "secondaryId": 0
         },
         "receipts": [
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68596CE72E15159BDCEA0FE3B7ECDAC89DC148C8B8B7FA49",
             "mosaicId": "6BED913FA20223F8",
             "amount": "129334920"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68693706B3EA603157D423C4F29ED6701CF70960E831D2AD",
             "mosaicId": "6BED913FA20223F8",
             "amount": "9238208"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "685F060B8CD3197D5DC270B61167EDD81749C4CBC3DF0EFA",
             "mosaicId": "6BED913FA20223F8",
             "amount": "46191042"
           },
           {
             "version": 1,
             "type": 20803,
             "mosaicId": "6BED913FA20223F8",
             "amount": "183764522"
           }
         ]
       },
       "id": "60A9BCD3DECE1274787108B4"
     },
     {
       "statement": {
         "height": "178610",
         "source": {
           "primaryId": 0,
           "secondaryId": 0
         },
         "receipts": [
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68596CE72E15159BDCEA0FE3B7ECDAC89DC148C8B8B7FA49",
             "mosaicId": "6BED913FA20223F8",
             "amount": "128647486"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68693706B3EA603157D423C4F29ED6701CF70960E831D2AD",
             "mosaicId": "6BED913FA20223F8",
             "amount": "9189106"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "6859ABB7C613FC3CB2D90E215798CA03A094C988A4E14923",
             "mosaicId": "6BED913FA20223F8",
             "amount": "45945530"
           },
           {
             "version": 1,
             "type": 20803,
             "mosaicId": "6BED913FA20223F8",
             "amount": "183764522"
           }
         ]
       },
       "id": "60A310C7DECE1274786F9836"
     },
     {
       "statement": {
         "height": "168289",
         "source": {
           "primaryId": 0,
           "secondaryId": 0
         },
         "receipts": [
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68596CE72E15159BDCEA0FE3B7ECDAC89DC148C8B8B7FA49",
             "mosaicId": "6BED913FA20223F8",
             "amount": "134397930"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68693706B3EA603157D423C4F29ED6701CF70960E831D2AD",
             "mosaicId": "6BED913FA20223F8",
             "amount": "9599852"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "6859ABB7C613FC3CB2D90E215798CA03A094C988A4E14923",
             "mosaicId": "6BED913FA20223F8",
             "amount": "47999260"
           },
           {
             "version": 1,
             "type": 20803,
             "mosaicId": "6BED913FA20223F8",
             "amount": "191997042"
           }
         ]
       },
       "id": "609E55BADECE1274786E8675"
     },
     {
       "statement": {
         "height": "148821",
         "source": {
           "primaryId": 0,
           "secondaryId": 0
         },
         "receipts": [
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68596CE72E15159BDCEA0FE3B7ECDAC89DC148C8B8B7FA49",
             "mosaicId": "6BED913FA20223F8",
             "amount": "134524980"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68693706B3EA603157D423C4F29ED6701CF70960E831D2AD",
             "mosaicId": "6BED913FA20223F8",
             "amount": "9608927"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "6859ABB7C613FC3CB2D90E215798CA03A094C988A4E14923",
             "mosaicId": "6BED913FA20223F8",
             "amount": "48044635"
           },
           {
             "version": 1,
             "type": 20803,
             "mosaicId": "6BED913FA20223F8",
             "amount": "191997042"
           }
         ]
       },
       "id": "609569F6DECE1274786CA1E5"
     },
     {
       "statement": {
         "height": "6433",
         "source": {
           "primaryId": 0,
           "secondaryId": 0
         },
         "receipts": [
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68596CE72E15159BDCEA0FE3B7ECDAC89DC148C8B8B7FA49",
             "mosaicId": "6BED913FA20223F8",
             "amount": "143702062"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "68693706B3EA603157D423C4F29ED6701CF70960E831D2AD",
             "mosaicId": "6BED913FA20223F8",
             "amount": "10264432"
           },
           {
             "version": 1,
             "type": 8515,
             "targetAddress": "6819CC8371F9C7E916D30F21AE1BF07B8A40DCA7EBB48A72",
             "mosaicId": "6BED913FA20223F8",
             "amount": "51322164"
           },
           {
             "version": 1,
             "type": 20803,
             "mosaicId": "6BED913FA20223F8",
             "amount": "191997042"
           }
         ]
       },
       "id": "6064C266983C6348AF29E910"
     }
   ],
   "pagination": {
     "pageNumber": 1,
     "pageSize": 20
   }
 }
 ​

But, like before, this is only the first page of results – there could be more. In order to get all transactions you would need to iterate through each page until there are no more entries. This could be done by adding the pageNumber to the URL and putting this inside a loop which incremented a counter to the page number variable and continued until no new results were found.

Finally we need to go through these results, find only “Harvest_Fee” receipts and print the block that the account harvested at and the harvest fee that they received. The code to do this is below. Remember that ADDRESS48 is the hexadecimal account address, ENUM_Harvest_Fee is decimal identifier for “Harvest_Fee” receipts and finally we need to divide the amount variable by 1 million to convert microXYM to XYM.

# We need to go through the results and find only those receipt types equal to "Harvest_Fee" which we store as ENUM_Harvest_Fee
# Then we print the block height and the amount of XYM harvested

for d in data['data']:
    height = d['statement']['height']
    for receipt in d['statement']['receipts']:
        if receipt['type'] == ENUM_Harvest_Fee and receipt['targetAddress'] == ADDRESS48:
            amount = int(receipt['amount'])/1000000
            print("height:{}, amount:{}".format(height, amount))

If we run this code we obtain the following results which show which blocks were harvested by our account and how much XYM they received as a harvesting fee. Simple!

height:224753, amount:128.635166
height:193175, amount:129.33492
height:178610, amount:128.647486
height:168289, amount:134.39793
height:148821, amount:134.52498
height:6433, amount:143.702062

Perfect! As usual I have included a link to my Jupyter Notebook – feel free to play around and write your own improvements, check your own account harvesting history and have fun! 😃

Avatar photo
NineLives
admin@symbolblog.com

I'm a Symbol and NEM enthusiast and run this blog to try to grow awareness of the platform in the English-speaking world. If you have any Symbol news you would like me to report on or you have an article that you would like to publish then please let me know!

2 Comments
  • rg911
    Posted at 19:46h, 15 July

    For the address part, perhaps it can also use the Symbol python SDK? https://github.com/symbol/symbol-sdk-core-python

    • Avatar photo
      XHarvesting
      Posted at 20:05h, 15 July

      Yes, this is what I hope we will get onto next. I was going to give it a go but got stuck as I couldn’t find much in the way of documentation at the time. I’d really like some clear beginner’s guide to the Python SDK, would be great! I think that the original author of this article may be covering it next and I will give it a go.