<center></center> This tutorial is part of a series where different aspects of programming with `EOS` are explained, the full curriculum can be found below. This part will focus on building an unending stream with fallback `api_endpoints` and goes into more depth about the `head_block` and `irreversible` blocks. --- #### Repository https://github.com/EOSIO/eos #### What will I learn - Head block & last irreversible block - Unending stream - Multiple api_endpoints and switching #### Requirements - Python3.6 #### Difficulty - basic --- ### Tutorial #### Setup Download the file from [Github](https://github.com/Juless89/eos-tutorials/tree/master/03). There is 1 file `stream_blocks.py`. Running the file without any arguments will test the `api_endpoints` for their speed to decide what node is best and then start streaming from the current `head_block`. Adding the argument `irreversible` will perform the same test but only stream `irreversible` blocks. Run scripts as following: `> python stream_blocks.py` #### Head block & last irreversible block On the `EOS` Blockchain new `blocks` are produced by 21 `block producers (BPs)` every halve a second. As this is not enough time for the `blocks` to propagate over the entire network `BPs` are chosen to produce a set amount of `blocks` before another `BP` takes the role as a `producer`. The frequency in which the `BPs` are chosen is based on the amount of votes this `BP` has received. This means that the current block producing `BP` is slightly ahead of the other `BPs`. For this reason there is a distinction between the `head_block` and the `last_irreversible_block`. Every `block` that has been verified by all` BPs` becomes an `irreversible block`. As it takes time for the `blocks` to propagate over the network and get verified by all `BPs` there is a delay before a `block` becomes `irreversible`. <center>  [eosnetworkmonitor](http://eosnetworkmonitor.io/) </center> Depending of the type of application use of the `head_block` or `last_irreversible_block` can be preferred. For example dealing with financial transaction using the `last_irreversible_block` is recommended, while building a chat application speed is more important so the current `head_block` is preferred. Information about the `head_block` and `last_irreversible_block` is found by using the `get_info` API request. ``` def get_head_block(self, irreversible=None): api_call = '/v1/chain/get_info' address = self.url + api_call request_json = self.s.get(url=address).json() if not irreversible: return request_json['head_block_num'] else: return request_json['last_irreversible_block_num'] ``` #### Unending stream Knowing this a robust unending stream can be made. First the `start_block` has to be decided. If none is given it is taken from the current `head_block` or `last_irreversible_block` which is set in `self.block`. This is to keep track of which blocks have been processed in case the stream crashes and needs to restart, starting at `self.block`. ``` self.block = self.get_head_block(irreversible) def stream_blocks(self, start_block=None, block_count=None, irreversible=None): if not start_block: start_block = self.block else: self.block = start_block ``` When upgrading code for the application where it has to be shut down it can be preferred to start at the last processed block. In which case a `start_block` can be set. <br> The next block of codes takes the `start_block` and then ask for the current `head_block` / `last_irreversible_block` to create a range of` blocks`. These `blocks` are requested and after the `start_block` is set to the last requested `block`. Repeating indefinitely. The upside of this is that it becomes impossible to request `blocks` ahead of the current `head_block` / `last_irreversible_block block`. The downside is that it requires additional API requests to retrieve the information about the `head_block` / `last_irreversible_block`. In the case of using the `last_irreversible_block` this is the only way to make sure the blocks being requested are `irreversible`. As it is possible to requests `blocks` ahead of the `last_irreversible_block`, so no error message would be returned if that were the case. ``` while True: head_block = self.get_head_block(irreversible) for n in range(start_block, head_block + 1): yield self.get_block(n) self.block += 1 start_block = head_block + 1 ``` In case something unexpected happens, such as losing internet connection the stream is put into a `while` loop with a `try` and `except` clause. This will keep trying to restart the stream. ``` while True: try: for block in self.stream_blocks(irreversible): print(f'\nBlock {self.block}') except Exception as error: time.sleep(60) print(repr(error)) ``` #### Multiple api_endpoints and switching Problems can also occur at the `api_endpoint` side. Proving additional `api_endpoints` to fall back to solves this problem. ``` self.nodes = ['http://mainnet.eoscanada.com', 'http://api-mainnet1.starteos.io', 'http://api.eosnewyork.io'] self.node_index = 0 self.url = self.nodes[self.node_index] ``` In the case the `api_endpoint` returns an unexpected error the `node_index` will be increased and adjusted to stay in the limits of the `nodes` list. The next `api_endpoint` is then selected and the session is renewed. ``` def reset_api_endpoint(self): self.node_index = (self.node_index + 1) % len(self.nodes) self.url = self.nodes[self.node_index] self.s = requests.Session() print(f'New api_endpoint: {self.url}') ``` Additionally when starting the stream all the nodes are tested for their response time. For each `api_endpoint` 100 `blocks` are retrieved and it is timed how long this process takes. The results are added to the results list as tuples `(url, time)`. Then the results are ordered by their time `sort(key=operator.itemgetter(1))`. Eventually a sorted nodes list is returned by stripping only the urls from the each tuple in results. ``` def test_api_endpoints(self): results = [] for url in self.nodes: self.url = url start_time = time.time() print(f'\nTesting: {url}') for block in self.stream_blocks(start_block=1, block_count=100): print(f'{self.block}/100', end='\r') end_time = time.time() - start_time results.append((url, end_time)) print(f'Took {end_time:.4} seconds for completion') results.sort(key=operator.itemgetter(1)) self.nodes = [node[0] for node in results] print(self.nodes) ``` #### Running the code The code can be run in two modes, either the current `head_block` mode or the `last_irreversible_block` mode. Regardless of the mode a test of each `api_endpoint` will first be conducted to sort the `api_endpoints` by their speed. ``` python stream_blocks.py irreversible Testing: http://mainnet.eoscanada.com Took 27.98 seconds for completion Testing: http://api-mainnet1.starteos.io Took 33.16 seconds for completion Testing: http://api.eosnewyork.io Took 29.68 seconds for completion ['http://mainnet.eoscanada.com', 'http://api.eosnewyork.io', 'http://api-mainnet1.starteos.io'] Mode: last_irreversible_block Block 5998244 ``` #### Curriculum - [Part 1: Using Python To Make API Requests To EOS Public API Endpoints](https://steemit.com/utopian-io/@steempytutorials/part-1-using-python-to-make-api-requests-to-eos-public-api-endpoints) - [Part 2: Streaming EOS Blocks With Python](https://steemit.com/utopian-io/@steempytutorials/part-2-streaming-eos-blocks-with-python) --- The code for this tutorial can be found on [GitHub](https://github.com/Juless89/eos-tutorials/tree/master/03)! This tutorial was written by @juliank.
author | steempytutorials |
---|---|
permlink | part-3-unending-block-stream-headblock-lastirreversibleblock-and-multiple-apiendpoint-support |
category | utopian-io |
json_metadata | {"tags":["utopian-io","tutorials","eos","programming","python"],"users":["juliank"],"image":["https://steemitimages.com/0x0/https://cdn.steemitimages.com/DQmeBnp3UNcivaVgrNiz6EZBQFQsJjnEKDx5mdzCtEABSBD/banner.png","https://cdn.steemitimages.com/DQmWze3XzAdvdtqKn1BGqfCkKJKvZhYpYTJ7EXaAuZPv9n2/Screenshot%202018-07-15%2011.59.17.png"],"links":["https://github.com/EOSIO/eos","https://github.com/Juless89/eos-tutorials/tree/master/03","http://eosnetworkmonitor.io/","https://steemit.com/utopian-io/@steempytutorials/part-1-using-python-to-make-api-requests-to-eos-public-api-endpoints","https://steemit.com/utopian-io/@steempytutorials/part-2-streaming-eos-blocks-with-python"],"app":"steemit/0.1","format":"markdown"} |
created | 2018-07-15 11:39:15 |
last_update | 2018-07-15 12:39:57 |
depth | 0 |
children | 5 |
last_payout | 2018-07-22 11:39:15 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 39.045 HBD |
curator_payout_value | 12.010 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 8,238 |
author_reputation | 31,094,047,689,691 |
root_title | "Part 3: Unending Block Stream, Head_block / Last_irreversible_Block and Multiple Api_endpoint Support" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 64,749,407 |
net_rshares | 23,471,672,514,364 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
paco-steem | 0 | 0 | 100% | ||
ace108 | 0 | 44,890,577,540 | 3% | ||
yuxi | 0 | 2,986,472,277 | 10% | ||
juliank | 0 | 123,357,645,317 | 50% | ||
upheaver | 0 | 1,371,051,697 | 6% | ||
makerhacks | 0 | 35,175,418,372 | 20% | ||
opaulo | 0 | 113,252,825,574 | 19% | ||
loshcat | 0 | 2,981,869,139 | 100% | ||
utopian-io | 0 | 22,916,746,784,133 | 14.8% | ||
greenorange | 0 | 609,471,115 | 100% | ||
r351574nc3 | 0 | 1,146,117,159 | 3% | ||
portugalcoin | 0 | 5,593,519,883 | 28% | ||
holger80 | 0 | 182,572,483,155 | 50% | ||
steempytutorials | 0 | 6,580,025,413 | 100% | ||
maxpatternman | 0 | 24,256,468,040 | 100% | ||
hevictor | 0 | 4,856,228,852 | 100% | ||
polbot | 0 | 223,313,914 | 100% | ||
properfraction | 0 | 602,700,623 | 100% | ||
hackerzizon | 0 | 204,496,913 | 1% | ||
sixoneninetimes | 0 | 75,587,368 | 10% | ||
statsexpert | 0 | 785,172,362 | 20% | ||
drsensor | 0 | 3,404,285,518 | 100% |
It is very technical..... Love @beingindian https://steemit.com/bitcoin/@beingindian/coindelta-flux-p2p-is-it-a-game-changer-in-crypto-world-4befa313469ff Upvote & comment & follow me for latest update.... βπΌ 
author | beingindian | ||||||
---|---|---|---|---|---|---|---|
permlink | re-steempytutorials-2018715t171525949z | ||||||
category | utopian-io | ||||||
json_metadata | {"tags":["utopian-io","tutorials","eos","programming","python"],"app":"esteem/1.6.0","format":"markdown+html","community":"esteem"} | ||||||
created | 2018-07-15 11:45:30 | ||||||
last_update | 2018-07-15 11:45:30 | ||||||
depth | 1 | ||||||
children | 0 | ||||||
last_payout | 2018-07-22 11:45:30 | ||||||
cashout_time | 1969-12-31 23:59:59 | ||||||
total_payout_value | 0.000 HBD | ||||||
curator_payout_value | 0.000 HBD | ||||||
pending_payout_value | 0.000 HBD | ||||||
promoted | 0.000 HBD | ||||||
body_length | 260 | ||||||
author_reputation | 17,254,908,620 | ||||||
root_title | "Part 3: Unending Block Stream, Head_block / Last_irreversible_Block and Multiple Api_endpoint Support" | ||||||
beneficiaries |
| ||||||
max_accepted_payout | 1,000,000.000 HBD | ||||||
percent_hbd | 10,000 | ||||||
post_id | 64,749,936 | ||||||
net_rshares | 0 |
Thank you for your contribution. - Put some comments on your code, plus the explanation you've already made. Your contribution has been evaluated according to [Utopian policies and guidelines](https://join.utopian.io/guidelines), as well as a predefined set of questions pertaining to the category. To view those questions and the relevant answers related to your post, [click here](https://review.utopian.io/result/8/21313323). ---- Need help? Write a ticket on https://support.utopian.io/. Chat with us on [Discord](https://discord.gg/uTyJkNm). [[utopian-moderator]](https://join.utopian.io/)
author | portugalcoin |
---|---|
permlink | re-steempytutorials-part-3-unending-block-stream-headblock-lastirreversibleblock-and-multiple-apiendpoint-support-20180715t223819722z |
category | utopian-io |
json_metadata | {"tags":["utopian-io"],"links":["https://join.utopian.io/guidelines","https://review.utopian.io/result/8/21313323","https://support.utopian.io/","https://discord.gg/uTyJkNm","https://join.utopian.io/"],"app":"steemit/0.1"} |
created | 2018-07-15 22:38:18 |
last_update | 2018-07-15 22:38:18 |
depth | 1 |
children | 1 |
last_payout | 2018-07-22 22:38:18 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.030 HBD |
curator_payout_value | 0.007 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 601 |
author_reputation | 598,828,312,571,988 |
root_title | "Part 3: Unending Block Stream, Head_block / Last_irreversible_Block and Multiple Api_endpoint Support" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 64,803,481 |
net_rshares | 18,115,744,955 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
juliank | 0 | 12,861,191,403 | 5% | ||
espoem | 0 | 5,254,553,552 | 5% |
Do you mean comments in the example code in the tutorial itself? As the code itself is commented.
author | juliank |
---|---|
permlink | re-portugalcoin-re-steempytutorials-part-3-unending-block-stream-headblock-lastirreversibleblock-and-multiple-apiendpoint-support-20180716t070926079z |
category | utopian-io |
json_metadata | {"tags":["utopian-io"],"app":"steemit/0.1"} |
created | 2018-07-16 07:09:24 |
last_update | 2018-07-16 07:09:24 |
depth | 2 |
children | 0 |
last_payout | 2018-07-23 07:09:24 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 97 |
author_reputation | 117,823,071,447,502 |
root_title | "Part 3: Unending Block Stream, Head_block / Last_irreversible_Block and Multiple Api_endpoint Support" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 64,837,496 |
net_rshares | 0 |
Congratulations @steempytutorials! You have completed the following achievement on Steemit and have been rewarded with new badge(s) : [](http://steemitboard.com/@steempytutorials) Award for the number of posts published <sub>_Click on the badge to view your Board of Honor._</sub> <sub>_If you no longer want to receive notifications, reply to this comment with the word_ `STOP`</sub> **Do not miss the last post from @steemitboard:** [SteemitBoard World Cup Contest - Final results coming soon](https://steemit.com/steemitboard/@steemitboard/steemitboard-world-cup-contest-final-contest-result-coming-soon) > Do you like [SteemitBoard's project](https://steemit.com/@steemitboard)? Then **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!
author | steemitboard |
---|---|
permlink | steemitboard-notify-steempytutorials-20180716t130247000z |
category | utopian-io |
json_metadata | {"image":["https://steemitboard.com/img/notify.png"]} |
created | 2018-07-16 13:02:45 |
last_update | 2018-07-16 13:02:45 |
depth | 1 |
children | 0 |
last_payout | 2018-07-23 13:02:45 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 918 |
author_reputation | 38,975,615,169,260 |
root_title | "Part 3: Unending Block Stream, Head_block / Last_irreversible_Block and Multiple Api_endpoint Support" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 64,867,328 |
net_rshares | 0 |
Hey @steempytutorials **Thanks for contributing on Utopian**. Weβre already looking forward to your next contribution! **Want to chat? Join us on Discord https://discord.gg/h52nFrV.** <a href='https://v2.steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1'>Vote for Utopian Witness!</a>
author | utopian-io |
---|---|
permlink | re-part-3-unending-block-stream-headblock-lastirreversibleblock-and-multiple-apiendpoint-support-20180716t122509z |
category | utopian-io |
json_metadata | "{"app": "beem/0.19.42"}" |
created | 2018-07-16 12:25:09 |
last_update | 2018-07-16 12:25:09 |
depth | 1 |
children | 0 |
last_payout | 2018-07-23 12:25:09 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 308 |
author_reputation | 152,955,367,999,756 |
root_title | "Part 3: Unending Block Stream, Head_block / Last_irreversible_Block and Multiple Api_endpoint Support" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 64,863,517 |
net_rshares | 5,254,553,552 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
espoem | 0 | 5,254,553,552 | 5% |