def commit(self): """Store the new height and along with block hash.""" self.abort_if_abci_chain_is_not_synced() data = self.block_txn_hash.encode('utf-8') # register a new block only when new transactions are received if self.block_txn_ids: self.bigchaindb.store_bulk_transactions(self.block_transactions) block = Block(app_hash=self.block_txn_hash, height=self.new_height, transactions=self.block_txn_ids) # NOTE: storing the block should be the last operation during commit # this effects crash recovery. Refer BEP#8 for details self.bigchaindb.store_block(block._asdict()) logger.debug('Commit-ing new block with hash: apphash=%s ,' 'height=%s, txn ids=%s', data, self.new_height, self.block_txn_ids) if self.events_queue: event = Event(EventTypes.BLOCK_VALID, { 'height': self.new_height, 'transactions': self.block_transactions }) self.events_queue.put(event) return ResponseCommit(data=data)
def commit(self): """Store the new height and along with block hash.""" self.abort_if_abci_chain_is_not_synced() data = self.block_txn_hash.encode('utf-8') # register a new block only when new transactions are received if self.block_txn_ids: self.bigchaindb.store_bulk_transactions(self.block_transactions) block = Block(app_hash=self.block_txn_hash, height=self.new_height, transactions=self.block_txn_ids) # NOTE: storing the block should be the last operation during commit # this effects crash recovery. Refer BEP#8 for details self.bigchaindb.store_block(block._asdict()) logger.debug( 'Commit-ing new block with hash: apphash=%s ,' 'height=%s, txn ids=%s', data, self.new_height, self.block_txn_ids) if self.events_queue: event = Event(EventTypes.BLOCK_VALID, { 'height': self.new_height, 'transactions': self.block_transactions }) self.events_queue.put(event) return ResponseCommit(data=data)
def test_chain_migration_election_show_shows_inconclusive(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] voter_keys = [v['private_key'] for v in validators] election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}, voter_keys) assert not run_election_show(Namespace(election_id=election.id), b) Election.process_block(b, 1, [election]) b.store_bulk_transactions([election]) assert run_election_show(Namespace(election_id=election.id), b) == \ 'status=ongoing' b.store_block(Block(height=1, transactions=[], app_hash='')._asdict()) b.store_validator_set(2, [v['storage'] for v in validators]) assert run_election_show(Namespace(election_id=election.id), b) == \ 'status=ongoing' b.store_block(Block(height=2, transactions=[], app_hash='')._asdict()) # TODO insert yet another block here when upgrading to Tendermint 0.22.4. assert run_election_show(Namespace(election_id=election.id), b) == \ 'status=inconclusive'
def test_info(b): r = RequestInfo(version=__tm_supported_versions__[0]) 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') app = App(b) 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') app = App(b) 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 init_chain(self, genesis): """Initialize chain with block of height 0""" validator_set = [decode_validator(v) for v in genesis.validators] block = Block(app_hash='', height=0, transactions=[]) self.bigchaindb.store_block(block._asdict()) self.bigchaindb.store_validator_set(1, validator_set) return ResponseInitChain()
def test_store_block(): from bigchaindb.backend import connect, query from bigchaindb.lib import Block conn = connect() block = Block(app_hash='random_utxo', height=3, transactions=[]) query.store_block(conn, block._asdict()) cursor = conn.db.blocks.find({}, projection={'_id': False}) assert cursor.count() == 1
def ongoing_validator_election_2(b, valid_upsert_validator_election_2, ed25519_node_keys): validators = b.get_validators(height=1) genesis_validators = {'validators': validators, 'height': 0, 'election_id': None} query.store_validator_set(b.connection, genesis_validators) b.store_bulk_transactions([valid_upsert_validator_election_2]) block_1 = Block(app_hash='hash_2', height=1, transactions=[valid_upsert_validator_election_2.id]) b.store_block(block_1._asdict()) return valid_upsert_validator_election_2
def test_get_block(): from bigchaindb.backend import connect, query from bigchaindb.lib import Block conn = connect() block = Block(app_hash='random_utxo', height=3, transactions=[]) conn.db.blocks.insert_one(block._asdict()) block = dict(query.get_block(conn, 3)) assert block['height'] == 3
def test_store_block(): from bigchaindb.backend import connect, query from bigchaindb.lib import Block conn = connect() block = Block(app_hash='random_utxo', height=3, transactions=[]) query.store_block(conn, block._asdict()) cursor = conn.db.blocks.find({}, projection={'_id': False}) assert cursor.count() == 1
def ongoing_election(b, valid_election, ed25519_node_keys): validators = b.get_validators(height=1) genesis_validators = {'validators': validators, 'height': 0, 'election_id': None} query.store_validator_set(b.connection, genesis_validators) b.store_bulk_transactions([valid_election]) block_1 = Block(app_hash='hash_1', height=1, transactions=[valid_election.id]) b.store_block(block_1._asdict()) return valid_election
def ongoing_validator_election(b, valid_upsert_validator_election, ed25519_node_keys): validators = b.get_validators(height=1) genesis_validators = {'validators': validators, 'height': 0} query.store_validator_set(b.connection, genesis_validators) b.store_bulk_transactions([valid_upsert_validator_election]) query.store_election(b.connection, valid_upsert_validator_election.id, 1, is_concluded=False) block_1 = Block(app_hash='hash_1', height=1, transactions=[valid_upsert_validator_election.id]) b.store_block(block_1._asdict()) return valid_upsert_validator_election
def test_get_block(): from bigchaindb.backend import connect, query from bigchaindb.lib import Block conn = connect() block = Block(app_hash='random_utxo', height=3, transactions=[]) conn.db.blocks.insert_one(block._asdict()) block = dict(query.get_block(conn, 3)) assert block['height'] == 3
def test_get_block_containing_transaction(b, client, alice): tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) block = Block(app_hash='random_utxo', height=13, transactions=[tx.id]) b.store_block(block._asdict()) res = client.get('{}?transaction_id={}'.format(BLOCKS_ENDPOINT, tx.id)) expected_response = [block.height] assert res.json == expected_response assert res.status_code == 200
def test_get_block_containing_transaction(b, client, alice): tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) block = Block(app_hash='random_utxo', height=13, transactions=[tx.id]) b.store_block(block._asdict()) res = client.get('{}?transaction_id={}'.format(BLOCKS_ENDPOINT, tx.id)) expected_response = [block.height] assert res.json == expected_response assert res.status_code == 200
def ongoing_validator_election(b, valid_upsert_validator_election, ed25519_node_keys): validators = b.get_validators(height=1) genesis_validators = {'validators': validators, 'height': 0} query.store_validator_set(b.connection, genesis_validators) b.store_bulk_transactions([valid_upsert_validator_election]) query.store_election(b.connection, valid_upsert_validator_election.id, 1, is_concluded=False) block_1 = Block(app_hash='hash_1', height=1, transactions=[valid_upsert_validator_election.id]) b.store_block(block_1._asdict()) return valid_upsert_validator_election
def init_chain(self, genesis): """Initialize chain upon genesis or a migration""" app_hash = '' height = 0 known_chain = self.bigchaindb.get_latest_abci_chain() if known_chain is not None: chain_id = known_chain['chain_id'] if known_chain['is_synced']: 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: validators = self.bigchaindb.get_validators() self.log_abci_migration_error(chain_id, validators) sys.exit(1) # set migration values for app hash and height block = self.bigchaindb.get_latest_block() app_hash = '' if block is None else block['app_hash'] height = 0 if block is None else block['height'] + 1 known_validators = self.bigchaindb.get_validators() validator_set = [ vutils.decode_validator(v) for v in genesis.validators ] if known_validators and known_validators != validator_set: self.log_abci_migration_error(known_chain['chain_id'], known_validators) sys.exit(1) block = Block(app_hash=app_hash, height=height, transactions=[]) self.bigchaindb.store_block(block._asdict()) self.bigchaindb.store_validator_set(height + 1, validator_set) abci_chain_height = 0 if known_chain is None else known_chain['height'] self.bigchaindb.store_abci_chain(abci_chain_height, genesis.chain_id, True) self.chain = { 'height': abci_chain_height, 'is_synced': True, 'chain_id': genesis.chain_id } return ResponseInitChain()
def inputs(user_pk, b, alice): from bigchaindb.models import Transaction # create blocks with transactions for `USER` to spend for height in range(1, 4): transactions = [ Transaction.create( [alice.public_key], [([user_pk], 1)], metadata={'msg': random.random()}, ).sign([alice.private_key]) for _ in range(10) ] tx_ids = [tx.id for tx in transactions] block = Block(app_hash='hash'+str(height), height=height, transactions=tx_ids) b.store_block(block._asdict()) b.store_bulk_transactions(transactions)
def test_end_block_return_validator_updates(b, init_chain_request): app = App(b) app.init_chain(init_chain_request) begin_block = RequestBeginBlock() app.begin_block(begin_block) # generate a block containing a concluded validator election validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) new_validator = generate_validators([1])[0] public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] voter_keys = [v['private_key'] for v in validators] election, votes = generate_election(b, ValidatorElection, public_key, private_key, new_validator['election'], voter_keys) b.store_block( Block(height=1, transactions=[election.id], app_hash='')._asdict()) b.store_bulk_transactions([election]) Election.process_block(b, 1, [election]) app.block_transactions = votes resp = app.end_block(RequestEndBlock(height=2)) assert resp.validator_updates[0].power == new_validator['election'][ 'power'] expected = bytes.fromhex(new_validator['election']['public_key']['value']) assert expected == resp.validator_updates[0].pub_key.data
def test_chain_migration_election_show_shows_concluded(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] voter_keys = [v['private_key'] for v in validators] election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}, voter_keys) assert not run_election_show(Namespace(election_id=election.id), b) b.store_bulk_transactions([election]) Election.process_block(b, 1, [election]) assert run_election_show(Namespace(election_id=election.id), b) == \ 'status=ongoing' b.store_abci_chain(1, 'chain-X') b.store_block( Block(height=1, transactions=[v.id for v in votes], app_hash='last_app_hash')._asdict()) Election.process_block(b, 2, votes) assert run_election_show(Namespace(election_id=election.id), b) == \ f'''status=concluded
def inputs(user_pk, b, alice): from bigchaindb.models import Transaction # create blocks with transactions for `USER` to spend for block in range(4): transactions = [ Transaction.create( [alice_pubkey(alice)], [([user_pk], 1)], metadata={ 'msg': random.random() }, ).sign([alice_privkey(alice)]).to_dict() for _ in range(10) ] block = Block(app_hash='', height=_get_height(b), transactions=transactions) b.store_block(block._asdict())
def test_get_block_endpoint(tb, client, alice): b = tb tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) tx = tx.sign([alice.private_key]) b.store_transaction(tx) block = Block(app_hash='random_utxo', height=31, transactions=[tx.id]) b.store_block(block._asdict()) res = client.get(BLOCKS_ENDPOINT + str(block.height)) expected_response = { 'height': block.height, 'transactions': [tx.to_dict()] } assert res.json == expected_response assert res.status_code == 200
def test_migrate_abci_chain_generates_new_chains(b, chain, block_height, expected): b.store_abci_chain(*chain) b.store_block( Block(app_hash='', height=block_height, transactions=[])._asdict()) b.migrate_abci_chain() latest_chain = b.get_latest_abci_chain() assert latest_chain == expected
def test_rollback_pre_commit_state_after_crash(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) b.store_block(Block(height=1, transactions=[], app_hash='')._asdict()) public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] voter_keys = [v['private_key'] for v in validators] migration_election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}, voter_keys) total_votes = votes txs = [migration_election, *votes] new_validator = generate_validators([1])[0] validator_election, votes = generate_election(b, ValidatorElection, public_key, private_key, new_validator['election'], voter_keys) total_votes += votes txs += [validator_election, *votes] b.store_bulk_transactions(txs) b.store_abci_chain(2, 'new_chain') b.store_validator_set(2, [v['storage'] for v in validators]) # TODO change to `4` when upgrading to Tendermint 0.22.4. b.store_validator_set(3, [new_validator['storage']]) b.store_election(migration_election.id, 2, is_concluded=False) b.store_election(validator_election.id, 2, is_concluded=True) # no pre-commit state rollback(b) for tx in txs: assert b.get_transaction(tx.id) assert b.get_latest_abci_chain() assert len(b.get_validator_change()['validators']) == 1 assert b.get_election(migration_election.id) assert b.get_election(validator_election.id) b.store_pre_commit_state({ 'height': 2, 'transactions': [tx.id for tx in txs] }) rollback(b) for tx in txs: assert not b.get_transaction(tx.id) assert not b.get_latest_abci_chain() assert len(b.get_validator_change()['validators']) == 4 assert len(b.get_validator_change(2)['validators']) == 4 assert not b.get_election(migration_election.id) assert not b.get_election(validator_election.id)
def init_chain(self, genesis): """Initialize chain upon genesis or a migration""" app_hash = '' height = 0 known_chain = self.bigchaindb.get_latest_abci_chain() if known_chain is not None: chain_id = known_chain['chain_id'] if known_chain['is_synced']: 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: validators = self.bigchaindb.get_validators() self.log_abci_migration_error(chain_id, validators) sys.exit(1) # set migration values for app hash and height block = self.bigchaindb.get_latest_block() app_hash = '' if block is None else block['app_hash'] height = 0 if block is None else block['height'] + 1 known_validators = self.bigchaindb.get_validators() validator_set = [vutils.decode_validator(v) for v in genesis.validators] if known_validators and known_validators != validator_set: self.log_abci_migration_error(known_chain['chain_id'], known_validators) sys.exit(1) block = Block(app_hash=app_hash, height=height, transactions=[]) self.bigchaindb.store_block(block._asdict()) self.bigchaindb.store_validator_set(height + 1, validator_set) abci_chain_height = 0 if known_chain is None else known_chain['height'] self.bigchaindb.store_abci_chain(abci_chain_height, genesis.chain_id, True) self.chain = {'height': abci_chain_height, 'is_synced': True, 'chain_id': genesis.chain_id} return ResponseInitChain()
def test_process_block_does_not_approve_after_validator_update(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) new_validator = generate_validators([1])[0] public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] voter_keys = [v['private_key'] for v in validators] election, votes = generate_election(b, ValidatorElection, public_key, private_key, new_validator['election'], voter_keys) txs = [election] total_votes = votes b.store_block( Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) Election.process_block(b, 1, txs) b.store_bulk_transactions(txs) second_election, second_votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}, voter_keys) Election.process_block(b, 2, total_votes + [second_election]) b.store_block( Block(height=2, transactions=[v.id for v in total_votes + [second_election]], app_hash='')._asdict()) b.store_abci_chain(1, 'chain-X') Election.process_block(b, 3, second_votes) assert not b.get_election(second_election.id)['is_concluded'] assert b.get_latest_abci_chain() == { 'height': 1, 'chain_id': 'chain-X', 'is_synced': True }
def inputs(user_pk, b, alice): from bigchaindb.models import Transaction # create blocks with transactions for `USER` to spend for height in range(1, 4): transactions = [ Transaction.create( [alice.public_key], [([user_pk], 1)], metadata={ 'msg': random.random() }, ).sign([alice.private_key]) for _ in range(10) ] tx_ids = [tx.id for tx in transactions] block = Block(app_hash='hash' + str(height), height=height, transactions=tx_ids) b.store_block(block._asdict()) b.store_bulk_transactions(transactions)
def test_run_recover(b, alice, bob): from bigchaindb.commands.bigchaindb import run_recover from bigchaindb.models import Transaction from bigchaindb.lib import Block, PreCommitState from bigchaindb.backend.query import PRE_COMMIT_ID from bigchaindb.backend import query tx1 = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}, metadata={'name': 'hohenheim'}) \ .sign([alice.private_key]) tx2 = Transaction.create([bob.public_key], [([bob.public_key], 1)], asset={'cycle': 'hero'}, metadata={'name': 'hohenheim'}) \ .sign([bob.private_key]) # store the transactions b.store_bulk_transactions([tx1, tx2]) # create a random block block8 = Block(app_hash='random_app_hash1', height=8, transactions=['txid_doesnt_matter'])._asdict() b.store_block(block8) # create the next block block9 = Block(app_hash='random_app_hash1', height=9, transactions=[tx1.id])._asdict() b.store_block(block9) # create a pre_commit state which is ahead of the commit state pre_commit_state = PreCommitState(commit_id=PRE_COMMIT_ID, height=10, transactions=[tx2.id])._asdict() b.store_pre_commit_state(pre_commit_state) run_recover(b) assert not query.get_transaction(b.connection, tx2.id)
def test_process_block_approves_after_pending_validator_update(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) new_validator = generate_validators([1])[0] public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] voter_keys = [v['private_key'] for v in validators] election, votes = generate_election(b, ValidatorElection, public_key, private_key, new_validator['election'], voter_keys) txs = [election] total_votes = votes another_validator = generate_validators([1])[0] election, votes = generate_election(b, ValidatorElection, public_key, private_key, another_validator['election'], voter_keys) txs += [election] total_votes += votes election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}, voter_keys) txs += [election] total_votes += votes b.store_abci_chain(1, 'chain-X') Election.process_block(b, 1, txs) b.store_block( Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) b.store_bulk_transactions(txs) Election.process_block(b, 2, total_votes) validators = b.get_validators() assert len(validators) == 5 assert new_validator['storage'] in validators assert another_validator['storage'] not in validators assert b.get_election(txs[0].id)['is_concluded'] assert not b.get_election(txs[1].id)['is_concluded'] assert b.get_election(txs[2].id)['is_concluded'] assert b.get_latest_abci_chain() == { 'height': 2, 'chain_id': 'chain-X-migrated-at-height-1', 'is_synced': False }
def commit(self): """Store the new height and along with block hash.""" data = self.block_txn_hash.encode('utf-8') # register a new block only when new transactions are received if self.block_txn_ids: self.bigchaindb.store_bulk_transactions(self.block_transactions) block = Block(app_hash=self.block_txn_hash, height=self.new_height, transactions=self.block_txn_ids) # NOTE: storing the block should be the last operation during commit # this effects crash recovery. Refer BEP#8 for details self.bigchaindb.store_block(block._asdict()) logger.debug( 'Commit-ing new block with hash: apphash=%s ,' 'height=%s, txn ids=%s', data, self.new_height, self.block_txn_ids) logger.benchmark('COMMIT_BLOCK, height:%s', self.new_height) return ResponseCommit(data=data)
def test_get_block_endpoint(b, client, alice): import copy tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) tx = tx.sign([alice.private_key]) # with store_bulk_transactions we use `insert_many` where PyMongo # automatically adds an `_id` field to the tx, therefore we need the # deepcopy, for more info see: # https://api.mongodb.com/python/current/faq.html#writes-and-ids tx_dict = copy.deepcopy(tx.to_dict()) b.store_bulk_transactions([tx]) block = Block(app_hash='random_utxo', height=31, transactions=[tx.id]) b.store_block(block._asdict()) res = client.get(BLOCKS_ENDPOINT + str(block.height)) expected_response = {'height': block.height, 'transactions': [tx_dict]} assert res.json == expected_response assert res.status_code == 200
def test_get_block_endpoint(b, client, alice): import copy tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) tx = tx.sign([alice.private_key]) # with store_bulk_transactions we use `insert_many` where PyMongo # automatically adds an `_id` field to the tx, therefore we need the # deepcopy, for more info see: # https://api.mongodb.com/python/current/faq.html#writes-and-ids tx_dict = copy.deepcopy(tx.to_dict()) b.store_bulk_transactions([tx]) block = Block(app_hash='random_utxo', height=31, transactions=[tx.id]) b.store_block(block._asdict()) res = client.get(BLOCKS_ENDPOINT + str(block.height)) expected_response = {'height': block.height, 'transactions': [tx_dict]} assert res.json == expected_response assert res.status_code == 200
def test_get_latest_block(b): from bigchaindb.lib import Block for i in range(10): app_hash = os.urandom(16).hex() txn_id = os.urandom(16).hex() block = Block(app_hash=app_hash, height=i, transactions=[txn_id])._asdict() b.store_block(block) block = b.get_latest_block() assert block['height'] == 9
def test_approved_elections_concludes_all_elections(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) new_validator = generate_validators([1])[0] public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] election, votes = generate_election(b, ValidatorElection, public_key, private_key, new_validator['election']) txs = [election] total_votes = votes election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}) txs += [election] total_votes += votes b.store_abci_chain(1, 'chain-X') b.store_block(Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) b.store_bulk_transactions(txs) Election.approved_elections(b, 1, total_votes) validators = b.get_validators() assert len(validators) == 5 assert new_validator['storage'] in validators chain = b.get_latest_abci_chain() assert chain assert chain == { 'height': 2, 'is_synced': False, 'chain_id': 'chain-X-migrated-at-height-1', } for tx in txs: election = b.get_election(tx.id) assert election
def test_process_block_approves_only_one_validator_update(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) new_validator = generate_validators([1])[0] public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] voter_keys = [v['private_key'] for v in validators] election, votes = generate_election(b, ValidatorElection, public_key, private_key, new_validator['election'], voter_keys) txs = [election] total_votes = votes another_validator = generate_validators([1])[0] election, votes = generate_election(b, ValidatorElection, public_key, private_key, another_validator['election'], voter_keys) txs += [election] total_votes += votes Election.process_block(b, 1, txs) b.store_block( Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) b.store_bulk_transactions(txs) Election.process_block(b, 2, total_votes) validators = b.get_validators() assert len(validators) == 5 assert new_validator['storage'] in validators assert another_validator['storage'] not in validators assert b.get_election(txs[0].id)['is_concluded'] assert not b.get_election(txs[1].id)['is_concluded']
def test_process_block_applies_only_one_migration(b): validators = generate_validators([1] * 4) b.store_validator_set(1, [v['storage'] for v in validators]) public_key = validators[0]['public_key'] private_key = validators[0]['private_key'] election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}) txs = [election] total_votes = votes election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}) txs += [election] total_votes += votes b.store_abci_chain(1, 'chain-X') Election.process_block(b, 1, txs) b.store_block(Block(height=1, transactions=[tx.id for tx in txs], app_hash='')._asdict()) b.store_bulk_transactions(txs) Election.process_block(b, 1, total_votes) chain = b.get_latest_abci_chain() assert chain assert chain == { 'height': 2, 'is_synced': False, 'chain_id': 'chain-X-migrated-at-height-1', } assert b.get_election(txs[0].id)['is_concluded'] assert not b.get_election(txs[1].id)['is_concluded']
def init_chain(self, validators): """Initialize chain with block of height 0""" block = Block(app_hash='', height=0, transactions=[]) self.bigchaindb.store_block(block._asdict()) return ResponseInitChain()
def test_init_chain_recognizes_new_chain_after_migration(b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) res = App(b).init_chain(request) assert res == ResponseInitChain() validator_set = query.get_validator_set(b.connection)['validators'] # simulate a migration query.store_block(b.connection, Block(app_hash='', height=1, transactions=[])._asdict()) b.migrate_abci_chain() # the same or other mismatching requests are ignored invalid_requests = [ request, generate_init_chain_request('unknown', validators), generate_init_chain_request('chain-XYZ'), generate_init_chain_request('chain-XYZ-migrated-at-height-1'), ] for r in invalid_requests: with pytest.raises(SystemExit): App(b).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': False, 'height': 2, } new_validator_set = query.get_validator_set(b.connection)['validators'] assert new_validator_set == validator_set # a request with the matching chain ID and matching validator set # completes the migration request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', validators) res = App(b).init_chain(request) assert res == ResponseInitChain() assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, 'height': 2, } assert query.get_latest_block(b.connection) == { 'height': 2, 'app_hash': '', 'transactions': [], } # requests with old chain ID and other requests are ignored invalid_requests = [ request, generate_init_chain_request('chain-XYZ', validators), generate_init_chain_request('chain-XYZ-migrated-at-height-1'), ] for r in invalid_requests: with pytest.raises(SystemExit): App(b).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, 'height': 2, } new_validator_set = query.get_validator_set(b.connection)['validators'] assert new_validator_set == validator_set assert query.get_latest_block(b.connection) == { 'height': 2, 'app_hash': '', 'transactions': [], }