Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 44 additions & 4 deletions bitshares/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ class Blockchain(object):
instance
:param str mode: (default) Irreversible block (``irreversible``) or
actual head block (``head``)
:param int max_block_wait_repetition: (default) 3 maximum wait time for next block
is max_block_wait_repetition * block_interval

This class let's you deal with blockchain related data and methods.
"""
def __init__(
self,
bitshares_instance=None,
mode="irreversible"
mode="irreversible",
max_block_wait_repetition=None
):
self.bitshares = bitshares_instance or shared_bitshares_instance()

Expand All @@ -29,6 +32,14 @@ def __init__(
else:
raise ValueError("invalid value for 'mode'!")

if max_block_wait_repetition:
self.max_block_wait_repetition = max_block_wait_repetition
else:
self.max_block_wait_repetition = 3

def is_irreversible_mode(self):
return self.mode == 'last_irreversible_block_num'

def info(self):
""" This call returns the *dynamic global properties*
"""
Expand Down Expand Up @@ -109,7 +120,7 @@ def blocks(self, start=None, stop=None):
confirmed by 2/3 of all block producers and is thus irreversible)
"""
# Let's find out how often blocks are generated!
block_interval = self.chainParameters().get("block_interval")
self.block_interval = self.chainParameters().get("block_interval")

if not start:
start = self.get_current_block_num()
Expand All @@ -126,7 +137,7 @@ def blocks(self, start=None, stop=None):
# Blocks from start until head block
for blocknum in range(start, head_block + 1):
# Get full block
block = self.bitshares.rpc.get_block(blocknum)
block = self.wait_for_and_get_block(blocknum)
block.update({"block_num": blocknum})
yield block
# Set new start
Expand All @@ -137,7 +148,36 @@ def blocks(self, start=None, stop=None):
return

# Sleep for one block
time.sleep(block_interval)
time.sleep(self.block_interval)

def wait_for_and_get_block(self, block_number, blocks_waiting_for=None):
""" Get the desired block from the chain, if the current head block is smaller (for both head and irreversible)
then we wait, but a maxmimum of blocks_waiting_for * max_block_wait_repetition time before failure.

:param int block_number: desired block number
:param int blocks_waiting_for: (default) difference between block_number and current head
how many blocks we are willing to wait, positive int
"""
if not blocks_waiting_for:
blocks_waiting_for = max(1, block_number - self.get_current_block_num())

repetition = 0
# can't return the block before the chain has reached it (support future block_num)
while self.get_current_block_num() < block_number:
repetition += 1
time.sleep(self.block_interval)
if repetition > blocks_waiting_for * self.max_block_wait_repetition:
raise Exception("Wait time for new block exceeded, aborting")
# block has to be returned properly
block = self.bitshares.rpc.get_block(block_number)
repetition = 0
while not block:
repetition += 1
time.sleep(self.block_interval)
if repetition > self.max_block_wait_repetition:
raise Exception("Wait time for new block exceeded, aborting")
block = self.bitshares.rpc.get_block(block_number)
return block

def ops(self, start=None, stop=None, **kwargs):
""" Yields all operations (including virtual operations) starting from
Expand Down