def test_put_tx_batch(self): tx_hash = create_hash_256() tx_index = 1 tx_batch = TransactionBatch(tx_hash) key = create_hash_256() tx_batch[key] = TransactionBatchValue(b'value', True, tx_index) key0 = create_hash_256() tx_batch[key0] = TransactionBatchValue(b'value0', True, tx_index) key1 = create_hash_256() tx_batch[key1] = TransactionBatchValue(b'value1', True, tx_index) key2 = create_hash_256() tx_batch[key2] = TransactionBatchValue(b'value2', True, tx_index) self.assertEqual(4, len(tx_batch)) self.block_batch.update(tx_batch) self.assertEqual(4, len(self.block_batch)) tx_index_2 = 2 tx_batch_2 = TransactionBatch(tx_hash) tx_batch_2[key] = TransactionBatchValue(b'updated_value', True, tx_index_2) self.block_batch.update(tx_batch_2) self.assertEqual(4, len(self.block_batch)) self.assertEqual(BlockBatchValue(b'value0', True, [tx_index]), self.block_batch[key0]) self.assertEqual(BlockBatchValue(b'value1', True, [tx_index]), self.block_batch[key1]) self.assertEqual(BlockBatchValue(b'value2', True, [tx_index]), self.block_batch[key2]) # As overwrite twice self.assertEqual( BlockBatchValue(b'updated_value', True, [tx_index, tx_index_2]), self.block_batch[key])
def test_put_tx_batch(self): tx_hash = create_hash_256() tx_batch = TransactionBatch(tx_hash) key = create_hash_256() tx_batch[key] = (b'value', True) key0 = create_hash_256() tx_batch[key0] = (b'value0', True) key1 = create_hash_256() tx_batch[key1] = (b'value1', True) key2 = create_hash_256() tx_batch[key2] = (b'value2', True) self.assertEqual(4, len(tx_batch)) tx_batch_2 = TransactionBatch(tx_hash) tx_batch_2[key] = (b'haha', True) self.block_batch.update(tx_batch_2) self.assertEqual(1, len(self.block_batch)) self.block_batch.update(tx_batch) self.assertEqual(4, len(self.block_batch)) self.assertEqual((b'value0', True), self.block_batch[key0]) self.assertEqual((b'value1', True), self.block_batch[key1]) self.assertEqual((b'value2', True), self.block_batch[key2]) self.assertEqual((b'value', True), self.block_batch[key])
def test_block_batch_update_tx_index(self): block_batch = self.block_batch overwrite_key = create_hash_256() last_value = None for i in range(3): last_value = b'value' + i.to_bytes(1, 'big') tx_batch = TransactionBatch(create_hash_256()) tx_batch[overwrite_key] = TransactionBatchValue( last_value, True, i) block_batch.update(tx_batch) tx_batch = TransactionBatch(create_hash_256()) tx_batch[overwrite_key] = TransactionBatchValue( b'reverted_value1', True, 3) tx_batch.revert_call() block_batch.update(tx_batch) tx_batch = TransactionBatch(create_hash_256()) tx_batch[overwrite_key] = TransactionBatchValue( b'reverted_value2', True, 4) tx_batch.clear() block_batch.update(tx_batch) actual_overwrite_value: 'BlockBatchValue' = block_batch.get( overwrite_key) assert actual_overwrite_value.value == last_value assert actual_overwrite_value.tx_indexes == [0, 1, 2]
def test_set_item(self): tx_batch = TransactionBatch() init_call_count = tx_batch.call_count self.assertEqual(0, len(tx_batch)) self.assertEqual(1, init_call_count) tx_batch[b'key0'] = TransactionBatchValue(b'value0', True) self.assertEqual(1, len(tx_batch)) tx_batch.enter_call() tx_batch[b'key1'] = TransactionBatchValue(b'value1', True) self.assertEqual(2, len(tx_batch)) self.assertEqual(init_call_count + 1, tx_batch.call_count) tx_batch.enter_call() tx_batch[b'key0'] = TransactionBatchValue(None, True) tx_batch[b'key1'] = TransactionBatchValue(b'key1', True) tx_batch[b'key2'] = TransactionBatchValue(b'value2', True) self.assertEqual(5, len(tx_batch)) self.assertEqual(init_call_count + 2, tx_batch.call_count) tx_batch.leave_call() self.assertEqual(4, len(tx_batch)) self.assertEqual(TransactionBatchValue(b'key1', True), tx_batch[b'key1']) self.assertEqual(init_call_count + 1, tx_batch.call_count) tx_batch.leave_call() self.assertEqual(3, len(tx_batch)) self.assertEqual(TransactionBatchValue(None, True), tx_batch[b'key0']) self.assertEqual(TransactionBatchValue(b'key1', True), tx_batch[b'key1']) self.assertEqual(TransactionBatchValue(b'value2', True), tx_batch[b'key2']) self.assertEqual(init_call_count, tx_batch.call_count)
def test_iter(self): tx_batch = TransactionBatch() tx_batch[b'key0'] = TransactionBatchValue(b'value0', True) tx_batch.enter_call() tx_batch[b'key1'] = TransactionBatchValue(b'value1', True) keys = [] for key in tx_batch: keys.append(key) self.assertEqual(b'key0', keys[0]) self.assertEqual(b'key1', keys[1])
def test_contains(self): tx_batch = TransactionBatch() init_call_count = tx_batch.call_count self.assertEqual(0, len(tx_batch)) self.assertEqual(1, init_call_count) tx_batch[b'key0'] = TransactionBatchValue(b'value0', True) self.assertEqual(1, len(tx_batch)) tx_batch.enter_call() tx_batch[b'key1'] = TransactionBatchValue(b'value1', True) self.assertEqual(2, len(tx_batch)) self.assertEqual(init_call_count + 1, tx_batch.call_count) tx_batch.enter_call() tx_batch[b'key0'] = TransactionBatchValue(None, True) tx_batch[b'key1'] = TransactionBatchValue(b'key1', True) tx_batch[b'key2'] = TransactionBatchValue(b'value2', True) self.assertEqual(5, len(tx_batch)) self.assertEqual(init_call_count + 2, tx_batch.call_count) keys = [b'key0', b'key1', b'key2'] for key in keys: self.assertTrue(key in tx_batch) keys = [b'key3', b'key4'] for key in keys: self.assertFalse(key in tx_batch) tx_batch = TransactionBatch() self.assertFalse(b'key' in tx_batch)
def setUp(self): db = Mock(spec=IconScoreDatabase) db.address = create_address(AddressPrefix.CONTRACT) context = IconScoreContext() context.icon_score_deploy_engine = Mock() traces = Mock(spec=list) context.tx = Mock(spec=Transaction) context.block = Mock(spec=Block) context.cumulative_step_used = Mock(spec=int) context.cumulative_step_used.attach_mock(Mock(), '__add__') context.step_counter = Mock(spec=IconScoreStepCounter) context.event_logs = [] context.traces = traces context.tx_batch = TransactionBatch() ContextContainer._push_context(context) InternalCall._other_score_call = Mock() IconScoreContext.icx_engine = Mock(spec=IcxEngine) IconScoreContext.icon_score_deploy_engine = Mock( spec=IconScoreDeployEngine) context.icon_score_mapper = Mock() context.icon_score_mapper.get_icon_score = Mock( return_value=TestScore(db)) self._score = TestScore(db)
def setUp(self): address = Address.from_data(AddressPrefix.CONTRACT, os.urandom(20)) db = Mock(spec=IconScoreDatabase) db.attach_mock(address, 'address') context = IconScoreContext() traces = Mock(spec=list) step_counter = Mock(spec=IconScoreStepCounter) IconScoreContext.engine = ContextEngine(icx=Mock(IcxEngine), deploy=Mock(DeployEngine), fee=None, iiss=None, prep=None, issue=None) IconScoreContext.storage = ContextStorage(icx=Mock(IcxStorage), deploy=Mock(DeployStorage), fee=None, iiss=None, prep=None, issue=None, rc=None, meta=None) IconScoreContext.icx_engine = Mock(spec=IcxEngine) context.type = IconScoreContextType.INVOKE context.func_type = IconScoreFuncType.WRITABLE context.tx_batch = TransactionBatch() context.event_logs = [] context.traces = traces context.step_counter = step_counter context.get_owner = Mock() ContextContainer._push_context(context) self._mock_score = EventlogScore(db)
def test_digest(self): block_batch = self.block_batch tx_batch = TransactionBatch(create_hash_256()) key0 = create_hash_256() tx_batch[key0] = TransactionBatchValue(b'value0', True) key1 = create_hash_256() tx_batch[key1] = TransactionBatchValue(b'value1', True) key2 = create_hash_256() tx_batch[key2] = TransactionBatchValue(b'value2', True) block_batch.update(tx_batch) data = [key0, b'value0', key1, b'value1', key2, b'value2'] expected = sha3_256(b'|'.join(data)) ret = block_batch.digest() self.assertEqual(expected, ret) tx_batch[key2] = TransactionBatchValue(None, True) block_batch.update(tx_batch) hash1 = block_batch.digest() tx_batch[key2] = TransactionBatchValue(b'', True) block_batch.update(tx_batch) hash2 = block_batch.digest() self.assertNotEqual(hash1, hash2)
def test_digest_with_excluded_data(self): block_batch = self.block_batch tx_batch = TransactionBatch(create_hash_256()) include_key1 = create_hash_256() tx_batch[include_key1] = TransactionBatchValue(b'value0', True) include_key2 = create_hash_256() tx_batch[include_key2] = TransactionBatchValue(b'value1', True) include_key3 = create_hash_256() tx_batch[include_key3] = TransactionBatchValue(b'', True) include_key4 = create_hash_256() tx_batch[include_key4] = TransactionBatchValue(None, True) exclude_key1 = create_hash_256() tx_batch[exclude_key1] = TransactionBatchValue(b'value2', False) exclude_key2 = create_hash_256() tx_batch[exclude_key2] = TransactionBatchValue(b'value3', False) block_batch.update(tx_batch) data = [ include_key1, b'value0', include_key2, b'value1', include_key3, b'', include_key4 ] expected = sha3_256(b'|'.join(data)) ret = block_batch.digest() self.assertEqual(expected, ret)
def test_tx_failure(self, score_invoke): score_invoke.side_effect = Mock( side_effect=InvalidParamsException("error")) from_ = Address.from_data(AddressPrefix.EOA, os.urandom(20)) to_ = Address.from_data(AddressPrefix.CONTRACT, os.urandom(20)) tx_index = randrange(0, 100) self._mock_context.tx = Transaction(os.urandom(32), tx_index, from_, to_, 0) self._mock_context.msg = Message(from_) self._mock_context.tx_batch = TransactionBatch() raise_exception_start_tag("test_tx_failure") tx_result = self._icon_service_engine._handle_icx_send_transaction( self._mock_context, { 'from': from_, 'to': to_ }) raise_exception_end_tag("test_tx_failure") self._icon_service_engine._charge_transaction_fee.assert_called() self.assertEqual(0, tx_result.status) self.assertEqual(tx_index, tx_result.tx_index) self.assertIsNone(tx_result.score_address) camel_dict = tx_result.to_dict(to_camel_case) self.assertNotIn('scoreAddress', camel_dict)
def test_tx_failure(self): self._icon_service_engine._icon_score_deploy_engine.attach_mock( Mock(return_value=False), 'is_data_type_supported') self._icon_service_engine._icon_score_engine. \ attach_mock(Mock(side_effect=IconServiceBaseException("error")), "invoke") from_ = Mock(spec=Address) to_ = Mock(spec=Address) tx_index = Mock(spec=int) self._mock_context.tx.attach_mock(tx_index, "index") self._mock_context.tx_batch = TransactionBatch() raise_exception_start_tag("test_tx_failure") tx_result = self._icon_service_engine._handle_icx_send_transaction( self._mock_context, {'from': from_, 'to': to_}) raise_exception_end_tag("test_tx_failure") self._icon_service_engine._charge_transaction_fee.assert_called() self.assertEqual(0, tx_result.status) self.assertEqual(tx_index, tx_result.tx_index) self.assertIsNone(tx_result.score_address) camel_dict = tx_result.to_dict(to_camel_case) self.assertNotIn('scoreAddress', camel_dict)
def context(): context = IconScoreContext(IconScoreContextType.DIRECT) context.tx_batch = TransactionBatch() context.block_batch = BlockBatch() ContextContainer._push_context(context) yield context ContextContainer._pop_context()
def _create_context(context_type: IconScoreContextType) -> IconScoreContext: context = context_factory.create(context_type) if context.type == IconScoreContextType.INVOKE: context.block_batch = BlockBatch() context.tx_batch = TransactionBatch() return context
def _create_context(context_type: IconScoreContextType) -> IconScoreContext: context = IconScoreContext(context_type) if context.type == IconScoreContextType.INVOKE: context.block_batch = BlockBatch() context.tx_batch = TransactionBatch() mock_block: 'Mock' = Mock(spec=Block) mock_block.attach_mock(Mock(return_value=0), 'height') context.block = mock_block return context
def test_iterable(self): tx_batch = TransactionBatch() init_call_count = tx_batch.call_count self.assertEqual(0, len(tx_batch)) self.assertEqual(1, init_call_count) tx_batch[b'key0'] = (b'value0', True) self.assertEqual(1, len(tx_batch)) block_batch = BlockBatch() block_batch.update(tx_batch) self.assertEqual((b'value0', True), block_batch[b'key0'])
def setUp(self): self.db_name = 'fee.db' self.address = create_address(AddressPrefix.EOA) db = ContextDatabase.from_path(self.db_name) self.assertIsNotNone(db) self.storage = FeeStorage(db) context = IconScoreContext(IconScoreContextType.DIRECT) context.tx_batch = TransactionBatch() context.block_batch = BlockBatch() self.context = context
def test_revert(self, mocker): mocker.patch.object(IconServiceEngine, "_charge_transaction_fee") mocker.patch.object(IconScoreEngine, "invoke") context = ContextContainer._get_context() icon_service_engine = IconServiceEngine() icon_service_engine._icx_engine = Mock(spec=IcxEngine) icon_service_engine._icon_score_deploy_engine = \ Mock(spec=DeployEngine) icon_service_engine._icon_pre_validator = Mock(spec=IconPreValidator) context.tx_batch = TransactionBatch() context.clear_batch = Mock() context.update_batch = Mock() from_ = Address.from_data(AddressPrefix.EOA, os.urandom(20)) to_ = Address.from_data(AddressPrefix.CONTRACT, os.urandom(20)) tx_index = randrange(0, 100) context.tx = Transaction(os.urandom(32), tx_index, from_, 0) context.msg = Message(from_) def intercept_charge_transaction_fee(*args, **kwargs): return {}, Mock(spec=int) IconServiceEngine._charge_transaction_fee.side_effect = \ intercept_charge_transaction_fee icon_service_engine._icon_score_deploy_engine.attach_mock( Mock(return_value=False), 'is_data_type_supported') reason = Mock(spec=str) code = ExceptionCode.SCORE_ERROR mock_revert = Mock(side_effect=IconScoreException(reason)) IconScoreEngine.invoke.side_effect = mock_revert raise_exception_start_tag("test_revert") tx_result = icon_service_engine._handle_icx_send_transaction( context, { 'version': 3, 'from': from_, 'to': to_ }) raise_exception_end_tag("test_revert") assert tx_result.status == 0 IconServiceEngine._charge_transaction_fee.assert_called() context.traces.append.assert_called() trace = context.traces.append.call_args[0][0] assert trace.trace == TraceType.REVERT assert trace.data[0] == code assert trace.data[1] == reason
def setUp(self): self.db_name = 'icx.db' self.address = create_address(AddressPrefix.EOA) db = ContextDatabase.from_path(self.db_name) self.assertIsNotNone(db) self.storage = IcxStorage(db) self.factory = IconScoreContextFactory(max_size=1) context = self.factory.create(IconScoreContextType.DIRECT) context.tx_batch = TransactionBatch() context.block_batch = BlockBatch() self.context = context
def test_get_item(self): byteorder = 'big' key = create_hash_256() tx_batch = TransactionBatch(create_hash_256()) tx_batch[key] = (b'value', True) self.block_batch.update(tx_batch) self.assertEqual((b'value', True), self.block_batch[key]) value = 100 tx_batch[key] = (value.to_bytes(8, byteorder), True) self.block_batch.update(tx_batch) self.assertEqual(value, int.from_bytes(self.block_batch[key][0], byteorder))
def test_throw(self, IconServiceEngine_charge_transaction_fee): context = ContextContainer._get_context() self._icon_service_engine = IconServiceEngine() self._icon_service_engine._flag = 0 self._icon_service_engine._icx_engine = Mock(spec=IcxEngine) self._icon_service_engine._icon_score_deploy_engine = \ Mock(spec=IconScoreDeployEngine) self._icon_service_engine._icon_score_engine = Mock( spec=IconScoreEngine) self._icon_service_engine._icon_pre_validator = Mock( spec=IconPreValidator) context.tx_batch = TransactionBatch() from_ = Mock(spec=Address) to_ = Mock(spec=Address) def intercept_charge_transaction_fee(*args, **kwargs): return Mock(spec=int), Mock(spec=int) IconServiceEngine_charge_transaction_fee.side_effect = \ intercept_charge_transaction_fee self._icon_service_engine._icon_score_deploy_engine.attach_mock( Mock(return_value=False), 'is_data_type_supported') error = Mock(spec=str) code = ExceptionCode.SCORE_ERROR mock_exception = Mock(side_effect=IconScoreException(error, code)) self._icon_service_engine._icon_score_engine.attach_mock( mock_exception, "invoke") raise_exception_start_tag("test_throw") tx_result = self._icon_service_engine._handle_icx_send_transaction( context, { 'version': 3, 'from': from_, 'to': to_ }) raise_exception_end_tag("test_throw") self.assertEqual(0, tx_result.status) IconServiceEngine_charge_transaction_fee.assert_called() context.traces.append.assert_called() trace = context.traces.append.call_args[0][0] self.assertEqual(TraceType.THROW, trace.trace) self.assertEqual(code, trace.data[0]) self.assertEqual(error, trace.data[1])
def block_batch(): block = Block(block_height=1, block_hash=create_block_hash(), timestamp=create_timestamp(), prev_hash=create_block_hash(), cumulative_fee=5) block_batch: 'BlockBatch' = BlockBatch(block) block_batch.block = block tx_batch: 'TransactionBatch' = TransactionBatch() for i, data in enumerate(DATA_LIST): tx_batch[create_hash_256()] = TransactionBatchValue(data, True, i) block_batch.update(tx_batch) return block_batch
def setUp(self): self.db_name = 'icx.db' db = ContextDatabase.from_path(self.db_name) self.assertIsNotNone(db) self.storage = IcxStorage(db) context = IconScoreContext(IconScoreContextType.DIRECT) context.tx_batch = TransactionBatch() mock_block: 'Mock' = Mock(spec=Block) mock_block.attach_mock(Mock(return_value=0), 'height') context.block = mock_block context.block_batch = BlockBatch() self.context = context
def test_throw(self, score_invoke, IconServiceEngine_charge_transaction_fee): context = ContextContainer._get_context() self._icon_service_engine = IconServiceEngine() self._icon_service_engine._icx_engine = Mock(spec=IcxEngine) self._icon_service_engine._icon_score_deploy_engine = \ Mock(spec=DeployEngine) self._icon_service_engine._icon_pre_validator = Mock( spec=IconPreValidator) context.tx_batch = TransactionBatch() context.clear_batch = Mock() context.update_batch = Mock() from_ = Address.from_data(AddressPrefix.EOA, os.urandom(20)) to_ = Address.from_data(AddressPrefix.CONTRACT, os.urandom(20)) tx_index = randrange(0, 100) context.tx = Transaction(os.urandom(32), tx_index, from_, 0) context.msg = Message(from_) def intercept_charge_transaction_fee(*args, **kwargs): return {}, Mock(spec=int) IconServiceEngine_charge_transaction_fee.side_effect = \ intercept_charge_transaction_fee self._icon_service_engine._icon_score_deploy_engine.attach_mock( Mock(return_value=False), 'is_data_type_supported') error = Mock(spec=str) code = ExceptionCode.INVALID_PARAMETER mock_exception = Mock(side_effect=InvalidParamsException(error)) score_invoke.side_effect = mock_exception raise_exception_start_tag("test_throw") tx_result = self._icon_service_engine._handle_icx_send_transaction( context, {'version': 3, 'from': from_, 'to': to_}) raise_exception_end_tag("test_throw") self.assertEqual(0, tx_result.status) IconServiceEngine_charge_transaction_fee.assert_called() context.traces.append.assert_called() trace = context.traces.append.call_args[0][0] self.assertEqual(TraceType.THROW, trace.trace) self.assertEqual(code, trace.data[0]) self.assertEqual(error, trace.data[1])
def context(score_db): context = IconScoreContext() context.icon_score_deploy_engine = Mock() traces = Mock(spec=list) context.tx = Mock(spec=Transaction) context.block = Mock(spec=Block) context.cumulative_step_used = Mock(spec=int) context.cumulative_step_used.attach_mock(Mock(), '__add__') context.step_counter = Mock(spec=IconScoreStepCounter) context.event_logs = [] context.traces = traces context.tx_batch = TransactionBatch() IconScoreContext.engine = ContextEngine(icx=Mock(spec=IcxEngine), deploy=Mock(spec=DeployEngine)) IconScoreContext.storage = ContextStorage(deploy=Mock(spec=DeployStorage)) context.icon_score_mapper = Mock() return context
def setUp(self): address = Address.from_data(AddressPrefix.CONTRACT, b'address') db = Mock(spec=IconScoreDatabase) db.attach_mock(address, 'address') context = IconScoreContext() traces = Mock(spec=list) step_counter = Mock(spec=IconScoreStepCounter) context.type = IconScoreContextType.INVOKE context.func_type = IconScoreFuncType.WRITABLE context.tx_batch = TransactionBatch() context.event_logs = [] context.traces = traces context.step_counter = step_counter context.get_owner = Mock() context.internal_call.icx_engine = Mock(spec=IcxEngine) ContextContainer._push_context(context) self._mock_score = EventlogScore(db)
def setUp(self): state_db_root_path = 'state_db' self.state_db_root_path = state_db_root_path rmtree(state_db_root_path) os.mkdir(state_db_root_path) address = Address.from_data(AddressPrefix.CONTRACT, b'score') context = IconScoreContext(IconScoreContextType.INVOKE) context.block_batch = BlockBatch() context.tx_batch = TransactionBatch() db_path = os.path.join(state_db_root_path, 'db') context_db = ContextDatabase.from_path(db_path, True) meta_context_db = MetaContextDatabase(context_db.key_value_db) self.context_db = context_db self.meta_context_db = meta_context_db self.address = address self.context = context
def setUp(self): state_db_root_path = 'state_db' self.state_db_root_path = state_db_root_path rmtree(state_db_root_path) os.mkdir(state_db_root_path) address = Address.from_data(AddressPrefix.CONTRACT, b'score') context_factory = IconScoreContextFactory(max_size=2) context = context_factory.create(IconScoreContextType.INVOKE) context.block_batch = BlockBatch() context.tx_batch = TransactionBatch() db_path = os.path.join(state_db_root_path, 'db') context_db = ContextDatabase.from_path(db_path, True) self.context_factory = context_factory self.context_db = context_db self.address = address self.context = context
def test_len(self): key = create_hash_256() tx_batch = TransactionBatch(create_hash_256()) tx_batch[key] = TransactionBatchValue(b'value0', True) self.block_batch.update(tx_batch) self.assertEqual(1, len(self.block_batch)) tx_batch[key] = TransactionBatchValue(b'value1', True) self.block_batch.update(tx_batch) self.assertEqual(1, len(self.block_batch)) key1 = create_hash_256() tx_batch[key1] = TransactionBatchValue(b'value0', True) self.block_batch.update(tx_batch) self.assertEqual(2, len(self.block_batch)) del self.block_batch[key] self.assertEqual(1, len(self.block_batch)) del self.block_batch[key1] self.assertEqual(0, len(self.block_batch))
def test_enter_call(self): tx_batch = TransactionBatch() call_count: int = tx_batch.call_count self.assertEqual(1, call_count) tx_batch.enter_call() self.assertEqual(call_count + 1, tx_batch.call_count) tx_batch[b'key'] = TransactionBatchValue(b'value', True) self.assertEqual(TransactionBatchValue(b'value', True), tx_batch[b'key']) tx_batch.leave_call() self.assertEqual(call_count, tx_batch.call_count) self.assertEqual(TransactionBatchValue(b'value', True), tx_batch[b'key']) tx_batch.enter_call() self.assertEqual(call_count + 1, tx_batch.call_count) tx_batch[b'id'] = TransactionBatchValue(b'hello', True) self.assertEqual(TransactionBatchValue(b'hello', True), tx_batch[b'id']) self.assertEqual(TransactionBatchValue(b'value', True), tx_batch[b'key']) tx_batch.revert_call() self.assertEqual(None, tx_batch[b'id']) self.assertEqual(TransactionBatchValue(b'value', True), tx_batch[b'key']) self.assertEqual(call_count + 1, tx_batch.call_count) tx_batch.leave_call() self.assertEqual(None, tx_batch[b'id']) self.assertEqual(TransactionBatchValue(b'value', True), tx_batch[b'key']) self.assertEqual(call_count, tx_batch.call_count)