mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Adjust ABCI handlers to shift migration height.
And abort if the current chain is not synced.
This commit is contained in:
parent
b5fe2b15ce
commit
cef559cdb0
@ -49,6 +49,19 @@ class App(BaseApplication):
|
||||
self.validators = None
|
||||
self.new_height = None
|
||||
|
||||
def log_abci_migration_error(self, chain_id, validators):
|
||||
logger.error(f'An ABCI chain migration is in process. ' +
|
||||
'Download the new ABCI client and configure it with ' +
|
||||
'chain_id={chain_id} and validators={validators}.')
|
||||
|
||||
def abort_if_abci_chain_is_not_synced(self, chain):
|
||||
if chain is None or chain['is_synced']:
|
||||
return
|
||||
|
||||
validators = self.bigchaindb.get_validators()
|
||||
self.log_abci_migration_error(chain['chain_id'], validators)
|
||||
sys.exit(1)
|
||||
|
||||
def init_chain(self, genesis):
|
||||
"""Initialize chain upon genesis or a migration"""
|
||||
|
||||
@ -60,17 +73,14 @@ class App(BaseApplication):
|
||||
chain_id = known_chain['chain_id']
|
||||
|
||||
if known_chain['is_synced']:
|
||||
msg = f'Ignoring the InitChain ABCI request ({genesis}) - ' + \
|
||||
msg = f'Got invalid InitChain ABCI request ({genesis}) - ' + \
|
||||
'the chain {chain_id} is already synced.'
|
||||
|
||||
logger.error(msg)
|
||||
sys.exit(1)
|
||||
|
||||
if chain_id != genesis.chain_id:
|
||||
msg = f'Got mismatching chain ID in the InitChain ' + \
|
||||
'ABCI request - you need to migrate the ABCI client ' + \
|
||||
'and set new chain ID: {chain_id}.'
|
||||
logger.error(msg)
|
||||
validators = self.bigchaindb.get_validators()
|
||||
self.log_abci_migration_error(chain_id, validators)
|
||||
sys.exit(1)
|
||||
|
||||
# set migration values for app hash and height
|
||||
@ -83,10 +93,8 @@ class App(BaseApplication):
|
||||
for v in genesis.validators]
|
||||
|
||||
if known_validators and known_validators != validator_set:
|
||||
msg = f'Got mismatching validator set in the InitChain ' + \
|
||||
'ABCI request - you need to migrate the ABCI client ' + \
|
||||
'and set new validator set: {known_validators}.'
|
||||
logger.error(msg)
|
||||
self.log_abci_migration_error(known_chain['chain_id'],
|
||||
known_validators)
|
||||
sys.exit(1)
|
||||
|
||||
block = Block(app_hash=app_hash, height=height, transactions=[])
|
||||
@ -99,10 +107,15 @@ class App(BaseApplication):
|
||||
|
||||
def info(self, request):
|
||||
"""Return height of the latest committed block."""
|
||||
|
||||
chain = self.bigchaindb.get_latest_abci_chain()
|
||||
self.abort_if_abci_chain_is_not_synced(chain)
|
||||
|
||||
r = ResponseInfo()
|
||||
block = self.bigchaindb.get_latest_block()
|
||||
if block:
|
||||
r.last_block_height = block['height']
|
||||
chain_shift = 0 if chain is None else chain['height']
|
||||
r.last_block_height = block['height'] - chain_shift
|
||||
r.last_block_app_hash = block['app_hash'].encode('utf-8')
|
||||
else:
|
||||
r.last_block_height = 0
|
||||
@ -117,6 +130,9 @@ class App(BaseApplication):
|
||||
raw_tx: a raw string (in bytes) transaction.
|
||||
"""
|
||||
|
||||
chain = self.bigchaindb.get_latest_abci_chain()
|
||||
self.abort_if_abci_chain_is_not_synced(chain)
|
||||
|
||||
logger.benchmark('CHECK_TX_INIT')
|
||||
logger.debug('check_tx: %s', raw_transaction)
|
||||
transaction = decode_transaction(raw_transaction)
|
||||
@ -135,8 +151,12 @@ class App(BaseApplication):
|
||||
req_begin_block: block object which contains block header
|
||||
and block hash.
|
||||
"""
|
||||
chain = self.bigchaindb.get_latest_abci_chain()
|
||||
self.abort_if_abci_chain_is_not_synced(chain)
|
||||
|
||||
chain_shift = 0 if chain is None else chain['height']
|
||||
logger.benchmark('BEGIN BLOCK, height:%s, num_txs:%s',
|
||||
req_begin_block.header.height,
|
||||
req_begin_block.header.height + chain_shift,
|
||||
req_begin_block.header.num_txs)
|
||||
|
||||
self.block_txn_ids = []
|
||||
@ -149,6 +169,10 @@ class App(BaseApplication):
|
||||
Args:
|
||||
raw_tx: a raw string (in bytes) transaction.
|
||||
"""
|
||||
|
||||
chain = self.bigchaindb.get_latest_abci_chain()
|
||||
self.abort_if_abci_chain_is_not_synced(chain)
|
||||
|
||||
logger.debug('deliver_tx: %s', raw_transaction)
|
||||
transaction = self.bigchaindb.is_valid_transaction(
|
||||
decode_transaction(raw_transaction), self.block_transactions)
|
||||
@ -170,7 +194,12 @@ class App(BaseApplication):
|
||||
height (int): new height of the chain.
|
||||
"""
|
||||
|
||||
height = request_end_block.height
|
||||
chain = self.bigchaindb.get_latest_abci_chain()
|
||||
self.abort_if_abci_chain_is_not_synced(chain)
|
||||
|
||||
chain_shift = 0 if chain is None else chain['height']
|
||||
|
||||
height = request_end_block.height + chain_shift
|
||||
self.new_height = height
|
||||
block_txn_hash = calculate_hash(self.block_txn_ids)
|
||||
block = self.bigchaindb.get_latest_block()
|
||||
@ -198,6 +227,9 @@ class App(BaseApplication):
|
||||
def commit(self):
|
||||
"""Store the new height and along with block hash."""
|
||||
|
||||
chain = self.bigchaindb.get_latest_abci_chain()
|
||||
self.abort_if_abci_chain_is_not_synced(chain)
|
||||
|
||||
data = self.block_txn_hash.encode('utf-8')
|
||||
|
||||
# register a new block only when new transactions are received
|
||||
|
||||
@ -11,6 +11,7 @@ from abci.types_pb2 import (
|
||||
PubKey,
|
||||
ResponseInitChain,
|
||||
RequestInitChain,
|
||||
RequestInfo,
|
||||
RequestBeginBlock,
|
||||
RequestEndBlock,
|
||||
Validator,
|
||||
@ -166,6 +167,39 @@ def test_init_chain_recognizes_new_chain_after_migration(b):
|
||||
}
|
||||
|
||||
|
||||
def test_info(b):
|
||||
r = RequestInfo()
|
||||
app = App(b)
|
||||
|
||||
res = app.info(r)
|
||||
assert res.last_block_height == 0
|
||||
assert res.last_block_app_hash == b''
|
||||
|
||||
b.store_block(Block(app_hash='1', height=1, transactions=[])._asdict())
|
||||
res = app.info(r)
|
||||
assert res.last_block_height == 1
|
||||
assert res.last_block_app_hash == b'1'
|
||||
|
||||
# simulate a migration and assert the height is shifted
|
||||
b.store_abci_chain(2, 'chain-XYZ')
|
||||
b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict())
|
||||
res = app.info(r)
|
||||
assert res.last_block_height == 0
|
||||
assert res.last_block_app_hash == b'2'
|
||||
|
||||
b.store_block(Block(app_hash='3', height=3, transactions=[])._asdict())
|
||||
res = app.info(r)
|
||||
assert res.last_block_height == 1
|
||||
assert res.last_block_app_hash == b'3'
|
||||
|
||||
# it's always the latest migration that is taken into account
|
||||
b.store_abci_chain(4, 'chain-XYZ-new')
|
||||
b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict())
|
||||
res = app.info(r)
|
||||
assert res.last_block_height == 0
|
||||
assert res.last_block_app_hash == b'4'
|
||||
|
||||
|
||||
def test_check_tx__signed_create_is_ok(b):
|
||||
from bigchaindb import App
|
||||
from bigchaindb.models import Transaction
|
||||
@ -199,7 +233,6 @@ def test_check_tx__unsigned_create_is_error(b):
|
||||
assert result.code == CodeTypeError
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_deliver_tx__valid_create_updates_db(b, init_chain_request):
|
||||
from bigchaindb import App
|
||||
from bigchaindb.models import Transaction
|
||||
@ -367,6 +400,16 @@ def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request):
|
||||
assert resp['height'] == 100
|
||||
assert resp['transactions'] == [tx.id]
|
||||
|
||||
# simulate a chain migration and assert the height is shifted
|
||||
b.store_abci_chain(100, 'new-chain')
|
||||
app.begin_block(begin_block)
|
||||
app.deliver_tx(encode_tx_to_bytes(tx))
|
||||
app.end_block(RequestEndBlock(height=1))
|
||||
resp = query.get_pre_commit_state(b.connection, PRE_COMMIT_ID)
|
||||
assert resp['commit_id'] == PRE_COMMIT_ID
|
||||
assert resp['height'] == 101
|
||||
assert resp['transactions'] == [tx.id]
|
||||
|
||||
|
||||
def test_new_validator_set(b):
|
||||
node1 = {'pub_key': {'type': 'ed25519',
|
||||
@ -389,3 +432,45 @@ def test_new_validator_set(b):
|
||||
'voting_power': u['power']})
|
||||
|
||||
assert updated_validator_set == updated_validators
|
||||
|
||||
|
||||
def test_info_aborts_if_chain_is_not_synced(b):
|
||||
b.store_abci_chain(0, 'chain-XYZ', False)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
App(b).info(RequestInfo())
|
||||
|
||||
|
||||
def test_check_tx_aborts_if_chain_is_not_synced(b):
|
||||
b.store_abci_chain(0, 'chain-XYZ', False)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
App(b).check_tx('some bytes')
|
||||
|
||||
|
||||
def test_begin_aborts_if_chain_is_not_synced(b):
|
||||
b.store_abci_chain(0, 'chain-XYZ', False)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
App(b).info(RequestBeginBlock())
|
||||
|
||||
|
||||
def test_deliver_tx_aborts_if_chain_is_not_synced(b):
|
||||
b.store_abci_chain(0, 'chain-XYZ', False)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
App(b).deliver_tx('some bytes')
|
||||
|
||||
|
||||
def test_end_block_aborts_if_chain_is_not_synced(b):
|
||||
b.store_abci_chain(0, 'chain-XYZ', False)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
App(b).info(RequestEndBlock())
|
||||
|
||||
|
||||
def test_commit_aborts_if_chain_is_not_synced(b):
|
||||
b.store_abci_chain(0, 'chain-XYZ', False)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
App(b).commit()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user