class Testcases(unittest.TestCase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.bts = BitShares( "wss://node.testnet.bitshares.eu", nobroadcast=True, keys={"active": wif, "owner": wif, "memo": wif}, ) # from getpass import getpass # self.bts.wallet.unlock(getpass()) set_shared_bitshares_instance(self.bts) self.bts.set_default_account("init0") def test_connect(self): self.bts.connect() def test_set_default_account(self): self.bts.set_default_account("init0") def test_info(self): info = self.bts.info() for key in ['current_witness', 'head_block_id', 'head_block_number', 'id', 'last_irreversible_block_num', 'next_maintenance_time', 'recently_missed_count', 'time']: self.assertTrue(key in info) def test_finalizeOps(self): bts = self.bts tx1 = bts.new_tx() tx2 = bts.new_tx() self.bts.transfer("init1", 1, core_unit, append_to=tx1) self.bts.transfer("init1", 2, core_unit, append_to=tx2) self.bts.transfer("init1", 3, core_unit, append_to=tx1) tx1 = tx1.json() tx2 = tx2.json() ops1 = tx1["operations"] ops2 = tx2["operations"] self.assertEqual(len(ops1), 2) self.assertEqual(len(ops2), 1) def test_transfer(self): bts = self.bts tx = bts.transfer( "1.2.8", 1.33, core_unit, memo="Foobar", account="1.2.7") self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "transfer" ) op = tx["operations"][0][1] self.assertIn("memo", op) self.assertEqual(op["from"], "1.2.7") self.assertEqual(op["to"], "1.2.8") amount = Amount(op["amount"]) self.assertEqual(float(amount), 1.33) def test_create_account(self): bts = self.bts name = ''.join(random.choice(string.ascii_lowercase) for _ in range(12)) key1 = PrivateKey() key2 = PrivateKey() key3 = PrivateKey() key4 = PrivateKey() tx = bts.create_account( name, registrar="init0", # 1.2.7 referrer="init1", # 1.2.8 referrer_percent=33, owner_key=format(key1.pubkey, core_unit), active_key=format(key2.pubkey, core_unit), memo_key=format(key3.pubkey, core_unit), additional_owner_keys=[format(key4.pubkey, core_unit)], additional_active_keys=[format(key4.pubkey, core_unit)], additional_owner_accounts=["committee-account"], # 1.2.0 additional_active_accounts=["committee-account"], proxy_account="init0", storekeys=False ) self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "account_create" ) op = tx["operations"][0][1] role = "active" self.assertIn( format(key4.pubkey, core_unit), [x[0] for x in op[role]["key_auths"]]) self.assertIn( format(key4.pubkey, core_unit), [x[0] for x in op[role]["key_auths"]]) self.assertIn( "1.2.0", [x[0] for x in op[role]["account_auths"]]) role = "owner" self.assertIn( format(key4.pubkey, core_unit), [x[0] for x in op[role]["key_auths"]]) self.assertIn( format(key4.pubkey, core_unit), [x[0] for x in op[role]["key_auths"]]) self.assertIn( "1.2.0", [x[0] for x in op[role]["account_auths"]]) self.assertEqual( op["options"]["voting_account"], "1.2.6") self.assertEqual( op["registrar"], "1.2.6") self.assertEqual( op["referrer"], "1.2.7") self.assertEqual( op["referrer_percent"], 33 * 100) def test_weight_threshold(self): bts = self.bts auth = {'account_auths': [['1.2.0', '1']], 'extensions': [], 'key_auths': [ ['TEST55VCzsb47NZwWe5F3qyQKedX9iHBHMVVFSc96PDvV7wuj7W86n', 1], ['TEST7GM9YXcsoAJAgKbqW2oVj7bnNXFNL4pk9NugqKWPmuhoEDbkDv', 1]], 'weight_threshold': 3} # threshold fine bts._test_weights_treshold(auth) auth = {'account_auths': [['1.2.0', '1']], 'extensions': [], 'key_auths': [ ['TEST55VCzsb47NZwWe5F3qyQKedX9iHBHMVVFSc96PDvV7wuj7W86n', 1], ['TEST7GM9YXcsoAJAgKbqW2oVj7bnNXFNL4pk9NugqKWPmuhoEDbkDv', 1]], 'weight_threshold': 4} # too high with self.assertRaises(ValueError): bts._test_weights_treshold(auth) def test_allow(self): bts = self.bts tx = bts.allow( "TEST55VCzsb47NZwWe5F3qyQKedX9iHBHMVVFSc96PDvV7wuj7W86n", weight=1, threshold=1, permission="owner" ) self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "account_update" ) op = tx["operations"][0][1] self.assertIn("owner", op) self.assertIn( ["TEST55VCzsb47NZwWe5F3qyQKedX9iHBHMVVFSc96PDvV7wuj7W86n", '1'], op["owner"]["key_auths"]) self.assertEqual(op["owner"]["weight_threshold"], 1) def test_disallow(self): bts = self.bts with self.assertRaisesRegex(ValueError, ".*Changes nothing.*"): bts.disallow( "TEST55VCzsb47NZwWe5F3qyQKedX9iHBHMVVFSc96PDvV7wuj7W86n", weight=1, threshold=1, permission="owner" ) with self.assertRaisesRegex(ValueError, ".*Changes nothing!.*"): bts.disallow( "TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", weight=1, threshold=1, permission="owner" ) def test_update_memo_key(self): bts = self.bts tx = bts.update_memo_key("TEST55VCzsb47NZwWe5F3qyQKedX9iHBHMVVFSc96PDvV7wuj7W86n") self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "account_update" ) op = tx["operations"][0][1] self.assertEqual( op["new_options"]["memo_key"], "TEST55VCzsb47NZwWe5F3qyQKedX9iHBHMVVFSc96PDvV7wuj7W86n") def test_approvewitness(self): bts = self.bts tx = bts.approvewitness("init0") self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "account_update" ) op = tx["operations"][0][1] self.assertIn( "1:0", op["new_options"]["votes"]) def test_approvecommittee(self): bts = self.bts tx = bts.approvecommittee("init0") self.assertEqual( getOperationNameForId(tx["operations"][0][0]), "account_update" ) op = tx["operations"][0][1] self.assertIn( "0:11", op["new_options"]["votes"]) def test_sign_message(self): def new_refresh(self): dict.__init__( self, {"name": "init0", "options": { "memo_key": "TEST6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" }}) with mock.patch( "bitshares.account.Account.refresh", new=new_refresh ): p = Message("message foobar").sign() Message(p).verify()
class NodeCall(): """ Concurent call a method for node.""" def __init__(self, node: str): """ Connect to a specified node.""" self.bts = BitShares(node) def call_wrapper(self, call, method: str, kwargs: dict): # Copy method from call to responce. result: dict = {"method": method} if not method or not call: result['error']: str = "" "`{0}` is not implemented!".format(method) else: try: # call can return dict, list, str result['result'] = call(self, **kwargs) except (RPCError, UnhandledRPCError) as err: result['error']: str = str(err) return result def get_global_properties(self): """ Retrieve the current global_property_object.""" return self.bts.info() def get_block(self, block_num: int): """ Retrieve a full, signed block.""" result = Block(block_num, blockchain_instance=self.bts) return dict(result) def get_chain_properties(self): """ Retrieve the chain_property_object associated with the chain.""" self.chain = Blockchain(blockchain_instance=self.bts) return self.chain.get_chain_properties() def get_dynamic_global_properties(self): """ This call returns the *dynamic global properties*.""" self.chain = Blockchain(blockchain_instance=self.bts) return self.chain.info() def get_config(self): """ Retrieve compile-time constants.""" self.chain = Blockchain(blockchain_instance=self.bts) return self.chain.config() def get_accounts(self, account_ids: list) -> list: """ Get a list of accounts by ID. :param str account_ids: Identify of the account :param bitshares.bitshares.BitShares blockchain_instance: BitShares instance :returns: Account data list :rtype: list :raises bitshares.exceptions.AccountDoesNotExistsException: if account does not exist """ result = [] for account_id in account_ids: account = Account(account_id, blockchain_instance=self.bts) result.append(dict(account)) return result def get_chain_id(self): """ Get the chain ID.""" self.chain = Blockchain(blockchain_instance=self.bts) return self.chain.get_chain_properties() def get_transaction(self, block_num: int, trx_in_block: int): """ Fetch an individual processed transaction from a block.""" result = self.bts.rpc.get_transaction(block_num, trx_in_block) return dict(result)
class NodeCalls(object): """ Connect to a specified node and perform calls.""" def __init__(self, scenario: dict, roundup: dict): self.scenario: dict = scenario self.roundup = roundup def connect(self, node: str, **kwargs): """ Connect to a specified node.""" self.bts = BitShares(node, kwargs) log.info('Connected to node "{0}".'.format(self.bts.rpc.url)) if not getattr(self, 'chain', None): self.chain = Blockchain(blockchain_instance=self.bts) def run(self): try: self.connect(self.scenario.get("node")) except BaseException as err: log.critical('Fail to connect to node "{0} due to {1}".'.format( self.scenario.get("node"), err) ) log.error('Scenario run has stopped.') return if not self.scenario or not self.scenario.get("stages", []): log.warning("Empty stages!") for stage in self.scenario.get("stages", []): start_time = time.time() method: str = stage.get("method", '') call = getattr(self, method, lambda: None) # Copy method from call to responce. result: dict = {"method": method} if not method or not call: result['result']['message']: str = "" "`{0}` is not implemented!".format(method) log.error(json.dumps(result, indent=(2 * ' '))) continue else: kwargs: dict = stage.get("params", {}) try: result['result']: str = call(**kwargs) log.info(json.dumps(result, indent=(2 * ' '))) except (RPCError, UnhandledRPCError) as err: result['result']['message']: str = str(err) log.error(json.dumps(result, indent=(2 * ' '))) # Track time spent on calls, sum up to table self.roundup[method] = self.roundup.get(method, 0) + time.time() - start_time def get_global_properties(self): """ Retrieve the current global_property_object.""" return self.bts.info() def get_block(self, block_num: int): """ Retrieve a full, signed block.""" return Block(block_num, blockchain_instance=self.bts, lazy=False) def get_chain_properties(self): """ Retrieve the chain_property_object associated with the chain.""" return self.chain.get_chain_properties() def get_dynamic_global_properties(self): """ This call returns the *dynamic global properties*.""" return self.chain.info() def get_config(self): """ Retrieve compile-time constants.""" return self.chain.config() # def get_all_accounts(self, start='', stop='', steps=1e3, **kwargs): # """ Yields account names between start and stop. # # :param str start: Start at this account name # :param str stop: Stop at this account name # :param int steps: Obtain ``steps`` ret with a single call from RPC # """ # return json.dumps((account for account in self.chain.get_all_accounts( # start, stop, steps)), iterable_as_array=True) def get_accounts(self, account_ids: list) -> list: """ Get a list of accounts by ID. :param str account_ids: Identify of the account :param bitshares.bitshares.BitShares blockchain_instance: BitShares instance :returns: Account data list :rtype: list :raises bitshares.exceptions.AccountDoesNotExistsException: if account does not exist """ result = [] for account_id in account_ids: account = Account(account_id, blockchain_instance=self.bts) result.append(account) return result def get_chain_id(self): """ Get the chain ID.""" return {"chain_id": self.chain.get_chain_properties()["chain_id"]} @log_exceptions def get_transaction(self, block_num: int, trx_in_block: int): """ Fetch an individual processed transaction from a block.""" return self.bts.rpc.get_transaction(block_num, trx_in_block) def get_proposed_transactions(self, account: str): """ Obtain a list of pending proposals for an account. :param str account: Account name :param bitshares blockchain_instance: BitShares() instance to use when accesing a RPC """ proposals: list = Proposals(account, blockchain_instance=self.bts) return {"proposed_transactions": proposals}