Skip to content

Commit

Permalink
Merge pull request #480 from olegtropinin/463-blockchain-managment-co…
Browse files Browse the repository at this point in the history
…mmand

Add blockchain management command for FileBlockchain.
  • Loading branch information
dmugtasimov authored Oct 30, 2021
2 parents dfadfac + b1dba99 commit d96525b
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from pprint import pformat

from django.core.management import BaseCommand

from thenewboston_node.business_logic.blockchain.base import BlockchainBase

GET_BLOCK = 'get-block'
GET_BLOCKS = 'get-blocks'
GET_BLOCKCHAIN_STATE = 'get-blockchain-state'

FILE_INTERFACE = 'file'
API_INTERFACE = 'api'


class Command(BaseCommand):
help = 'Blockchain managements commands' # noqa: A003

def __init__(self, *args, **kwargs):
self.blockchain = None
super().__init__(*args, **kwargs)

def add_arguments(self, parser):
parser.add_argument(
'--interface',
type=str,
choices=[FILE_INTERFACE, API_INTERFACE],
default=FILE_INTERFACE,
help='Select one of possible blockchain interface'
)

subparsers = parser.add_subparsers(title='Blockchain management commands', dest='command', required=True)

get_block_parser = subparsers.add_parser(GET_BLOCK, help='Print block JSON by block number')
get_block_parser.add_argument('block_number', nargs='?', type=int)

get_blocks_parser = subparsers.add_parser(GET_BLOCKS, help='Print range of block JSONs by block numbers')
get_blocks_parser.add_argument('start_block', nargs='?', type=int)
get_blocks_parser.add_argument('end_block', nargs='?', type=int)

get_blockchain_state_parser = subparsers.add_parser(
GET_BLOCKCHAIN_STATE, help='Print blockchain state by block number'
)
get_blockchain_state_parser.add_argument('block_number', nargs='?', type=int)

def handle(self, interface, *args, **options):
interfaces = {
FILE_INTERFACE: self.init_file_blockchain,
API_INTERFACE: self.init_api_blockchain,
}

init_interface = interfaces[interface]
init_interface()
assert self.blockchain is not None

commands = {
GET_BLOCK: self.print_block,
GET_BLOCKS: self.print_blocks,
GET_BLOCKCHAIN_STATE: self.print_blockchain_state,
}
exec_command = commands[options['command']]
exec_command(*args, **options)

def init_file_blockchain(self):
self.blockchain = BlockchainBase.get_instance()

def init_api_blockchain(self):
raise NotImplementedError('Must be implemented soon')

def print_block(self, block_number, *args, **options):
block = self.blockchain.get_block_by_number(block_number)
if block is None:
return
self._print_blockchain_model(block)

def print_blocks(self, start_block, end_block, *args, **options):
if start_block > end_block:
self.stdout.write(self.style.ERROR('End block argument should be equal or more than start block.'))
return

for block in self.blockchain.yield_blocks_from(start_block):
self._print_blockchain_model(block)

def print_blockchain_state(self, block_number, *args, **options):
state = self.blockchain.get_blockchain_state_by_block_number(block_number)
self._print_blockchain_model(state)

def _print_blockchain_model(self, blockchain_model):
serialized_model = blockchain_model.serialize_to_dict()
self.stdout.write(pformat(serialized_model))
75 changes: 75 additions & 0 deletions thenewboston_node/core/tests/test_thenewboston_blockchain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from functools import partial
from io import StringIO
from unittest.mock import patch

from django.core.management import call_command

from thenewboston_node.business_logic.blockchain.base import BlockchainBase


class TestThenewbostonBlockchain:
run_command = partial(call_command, 'thenewboston_blockchain')

def test_get_block(self, file_blockchain_with_three_block_chunks):
with patch.object(
BlockchainBase, 'get_instance', return_value=file_blockchain_with_three_block_chunks
) as mock_method:
out = StringIO()
self.run_command('get-block', 2, stdout=out)
assert "'block_number': 2" in out.getvalue()
mock_method.assert_called_once()

def test_get_block_when_block_is_missed(self, file_blockchain_with_three_block_chunks):
with patch.object(
BlockchainBase, 'get_instance', return_value=file_blockchain_with_three_block_chunks
) as mock_method:
out = StringIO()
self.run_command('get-block', 10, stdout=out)
assert out.getvalue() == ''
mock_method.assert_called_once()

def test_get_blocks(self, file_blockchain_with_three_block_chunks):
with patch.object(
BlockchainBase, 'get_instance', return_value=file_blockchain_with_three_block_chunks
) as mock_method:
out = StringIO()
self.run_command('get-blocks', 2, 3, stdout=out)
assert "'block_number': 2" in out.getvalue()
assert "'block_number': 3" in out.getvalue()
mock_method.assert_called_once()

def test_get_blocks_when_blocks_are_missed(self, file_blockchain_with_three_block_chunks):
with patch.object(
BlockchainBase, 'get_instance', return_value=file_blockchain_with_three_block_chunks
) as mock_method:
out = StringIO()
self.run_command('get-blocks', 10, 11, stdout=out)
assert out.getvalue() == ''
mock_method.assert_called_once()

def test_get_blocks_when_start_and_end_block_are_equal(self, file_blockchain_with_three_block_chunks):
with patch.object(
BlockchainBase, 'get_instance', return_value=file_blockchain_with_three_block_chunks
) as mock_method:
out = StringIO()
self.run_command('get-blocks', 2, 2, stdout=out)
assert "'block_number\': 2" in out.getvalue()
mock_method.assert_called_once()

def test_get_blocks_when_start_number_is_high_than_end_number(self, file_blockchain_with_three_block_chunks):
with patch.object(
BlockchainBase, 'get_instance', return_value=file_blockchain_with_three_block_chunks
) as mock_method:
out = StringIO()
self.run_command('get-blocks', 3, 2, stdout=out)
assert 'End block argument should be equal or more than start block.' in out.getvalue()
mock_method.assert_called_once()

def test_get_blockchain_state(self, file_blockchain_with_three_block_chunks):
with patch.object(
BlockchainBase, 'get_instance', return_value=file_blockchain_with_three_block_chunks
) as mock_method:
out = StringIO()
self.run_command('get-blockchain-state', 2, stdout=out)
assert "{'message': {'account_states'" in out.getvalue()
mock_method.assert_called_once()

0 comments on commit d96525b

Please sign in to comment.