Example #1
0
    def test_gateway_handler(self):
        bitshares = BitShares(settings.BITSHARES_NODE_URL,
                              nobroadcast=settings.BLOCKCHAIN_NOBROADCAST,
                              keys=[settings.BITSHARES_GATEWAY_WIF])
        bitshares.set_default_account(settings.BITSHARES_GATEWAY_ACCOUNT)

        transnet = Transnet(settings.TRANSNET_NODE_URL,
                            nobroadcast=settings.BLOCKCHAIN_NOBROADCAST,
                            keys={
                                'active': settings.TRANSNET_GATEWAY_WIF,
                                'memo': settings.TRANSNET_GATEWAY_WIF_MEMO
                            })
        transnet.set_default_account(settings.TRANSNET_GATEWAY_ACCOUNT)

        transaction = BitsharesTransnetTransaction.objects.create(
            trx_id='test',
            trx_in_block=3,
            op_in_trx=3,
            asset='UTECH.UTCORE',
            amount=pow(10, 5),
            account_external='superpchelka23',
            account_internal='superpchelka23')

        handler = BitsharesGatewayHandler(bitshares,
                                          settings.BITSHARES_GATEWAY_ACCOUNT,
                                          transnet,
                                          settings.TRANSNET_GATEWAY_ACCOUNT,
                                          settings.TRANSNET_GATEWAY_WIF_MEMO,
                                          {'UTECH.UTCORE': 'UTECH.UTCORE'})

        handler.handle([transaction], lambda: True)

        self.assertTrue(transaction.closed,
                        'Transaction must be properly processed')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.bts = Transnet("wss://node.testnet.transnet.eu",
                            nobroadcast=True,
                            keys={"active": wif})
        set_shared_transnet_instance(self.bts)
        self.bts.set_default_account("init0")
Example #3
0
class Testcases(unittest.TestCase):

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

        self.bts = Transnet(
            "wss://node.testnet.transnet.eu",
            nobroadcast=True,
            # We want to bundle many operations into a single transaction
            bundle=True,
            # Overwrite wallet to use this list of wifs only
            wif={"active": wif}
        )
        self.bts.set_default_account("init0")
        set_shared_transnet_instance(self.bts)

    def test_account(self):
        Account("witness-account")
        Account("1.2.3")
        asset = Asset("1.3.0")
        symbol = asset["symbol"]
        account = Account("witness-account", full=True)
        self.assertEqual(account.name, "witness-account")
        self.assertEqual(account["name"], account.name)
        self.assertEqual(account["id"], "1.2.1")
        self.assertIsInstance(account.balance("1.3.0"), Amount)
        # self.assertIsInstance(account.balance({"symbol": symbol}), Amount)
        self.assertIsInstance(account.balances, list)
        for h in account.history(limit=1):
            pass

        # BlockchainObjects method
        account.cached = False
        self.assertTrue(account.items())
        account.cached = False
        self.assertIn("id", account)
        account.cached = False
        self.assertEqual(account["id"], "1.2.1")
        self.assertEqual(str(account), "<Account 1.2.1>")
        self.assertIsInstance(Account(account), Account)

    def test_account_upgrade(self):
        account = Account("witness-account")
        tx = account.upgrade()
        ops = tx["operations"]
        op = ops[0][1]
        self.assertEqual(len(ops), 1)
        self.assertEqual(
            getOperationNameForId(ops[0][0]),
            "account_upgrade"
        )
        self.assertTrue(
            op["upgrade_to_lifetime_member"]
        )
        self.assertEqual(
            op["account_to_upgrade"],
            "1.2.1",
        )
Example #4
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.bts = Transnet(
            nobroadcast=True,
            # We want to bundle many operations into a single transaction
            bundle=True,
            # Overwrite wallet to use this list of wifs only
            wif=[wif])
        self.bts.set_default_account("init0")
        set_shared_transnet_instance(self.bts)
Example #5
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.bts = Transnet(
            "wss://node.testnet.transnet.eu",
            nobroadcast=True,
            keys={"active": wif},
        )
        # from getpass import getpass
        # self.trns.wallet.unlock(getpass())
        set_shared_transnet_instance(self.bts)
        self.bts.set_default_account("init0")
Example #6
0
    def __init__(self):
        self.site_settings = SettingsModel.load()
        self.transnet = Transnet(
            self.site_settings.transnet_bitshares_node_url,
            nobroadcast=settings.BLOCKCHAIN_NOBROADCAST,
            keys={
                'active': self.site_settings.transnet_bitshares_active_wif,
            })
        self.transnet.set_default_account(
            self.site_settings.transnet_bitshares_gateway_address)

        super(TransnetBasedGateway, self).__init__()
 def __init__(self, *args, **kwargs):
     super(Testcases, self).__init__(*args, **kwargs)
     transnet = Transnet(
         "wss://transnet.space:10443/ws",
         nobroadcast=True,
     )
     set_shared_transnet_instance(transnet)
Example #8
0
    def test_account_listener(self):
        self.transnet = Transnet(settings.TRANSNET_NODE_URL,
                                 nobroadcast=settings.BLOCKCHAIN_NOBROADCAST,
                                 keys={
                                     'active': settings.TRANSNET_GATEWAY_WIF,
                                     'memo': settings.TRANSNET_GATEWAY_WIF_MEMO
                                 })

        handler = TestAccountListenerHandler()
        transfers_provider = TransnetAccountTransfersProvider(
            self.transnet, settings.TRANSNET_GATEWAY_WIF_MEMO,
            settings.TRANSNET_GATEWAY_ACCOUNT, TransnetBitsharesTransaction)
        transfer_listener = AccountTransfersListener(transfers_provider)
        transfer_listener.add_handler(handler)

        threading.Thread(target=lambda: transfer_listener.start()).start()
        max_waiting_seconds = 15
        start_time = now()

        while not handler.processed and (
                now() - start_time).seconds < max_waiting_seconds:
            pass

        transfer_listener.stop()
        self.assertTrue(handler.processed, 'No one transactions were handled')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.bts = Transnet(
            "wss://node.testnet.transnet.eu",
            nobroadcast=True,
        )
        set_shared_transnet_instance(self.bts)
        self.asset = Asset("1.3.0")
        self.symbol = self.asset["symbol"]
        self.precision = self.asset["precision"]
        self.asset2 = Asset("1.3.1")
Example #10
0
class Testcases(unittest.TestCase):

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

        self.bts = Transnet(
            "wss://node.testnet.transnet.eu",
            nobroadcast=True,
            keys={"active": wif},
        )
        # from getpass import getpass
        # self.trns.wallet.unlock(getpass())
        set_shared_transnet_instance(self.bts)
        self.bts.set_default_account("init0")

    def test_finalizeOps_proposal(self):
        bts = self.bts
        # proposal = trns.new_proposal(trns.tx())
        proposal = bts.proposal()
        self.bts.transfer("init1", 1, "TEST", append_to=proposal)
        tx = bts.tx().json()  # default tx buffer
        ops = tx["operations"]
        self.assertEqual(len(ops), 1)
        self.assertEqual(
            getOperationNameForId(ops[0][0]),
            "proposal_create")
        prop = ops[0][1]
        self.assertEqual(len(prop["proposed_ops"]), 1)
        self.assertEqual(
            getOperationNameForId(prop["proposed_ops"][0]["op"][0]),
            "transfer")

    def test_finalizeOps_proposal2(self):
        bts = self.bts
        proposal = bts.new_proposal()
        # proposal = trns.proposal()
        self.bts.transfer("init1", 1, "TEST", append_to=proposal)
        tx = bts.tx().json()  # default tx buffer
        ops = tx["operations"]
        self.assertEqual(len(ops), 1)
        self.assertEqual(
            getOperationNameForId(ops[0][0]),
            "proposal_create")
        prop = ops[0][1]
        self.assertEqual(len(prop["proposed_ops"]), 1)
        self.assertEqual(
            getOperationNameForId(prop["proposed_ops"][0]["op"][0]),
            "transfer")

    def test_finalizeOps_combined_proposal(self):
        bts = self.bts
        parent = bts.new_tx()
        proposal = bts.new_proposal(parent)
        self.bts.transfer("init1", 1, "TEST", append_to=proposal)
        self.bts.transfer("init1", 1, "TEST", append_to=parent)
        tx = parent.json()
        ops = tx["operations"]
        self.assertEqual(len(ops), 2)
        self.assertEqual(
            getOperationNameForId(ops[0][0]),
            "proposal_create")
        self.assertEqual(
            getOperationNameForId(ops[1][0]),
            "transfer")
        prop = ops[0][1]
        self.assertEqual(len(prop["proposed_ops"]), 1)
        self.assertEqual(
            getOperationNameForId(prop["proposed_ops"][0]["op"][0]),
            "transfer")

    def test_finalizeOps_changeproposer_new(self):
        bts = self.bts
        proposal = bts.proposal(proposer="init5")
        bts.transfer("init1", 1, "TEST", append_to=proposal)
        tx = bts.tx().json()
        ops = tx["operations"]
        self.assertEqual(len(ops), 1)
        self.assertEqual(
            getOperationNameForId(ops[0][0]),
            "proposal_create")
        prop = ops[0][1]
        self.assertEqual(len(prop["proposed_ops"]), 1)
        self.assertEqual(prop["fee_paying_account"], "1.2.11")
        self.assertEqual(
            getOperationNameForId(prop["proposed_ops"][0]["op"][0]),
            "transfer")

    def test_finalizeOps_changeproposer_legacy(self):
        bts = self.bts
        bts.proposer = "init5"
        tx = bts.transfer("init1", 1, "TEST")
        ops = tx["operations"]
        self.assertEqual(len(ops), 1)
        self.assertEqual(
            getOperationNameForId(ops[0][0]),
            "proposal_create")
        prop = ops[0][1]
        self.assertEqual(len(prop["proposed_ops"]), 1)
        self.assertEqual(prop["fee_paying_account"], "1.2.11")
        self.assertEqual(
            getOperationNameForId(prop["proposed_ops"][0]["op"][0]),
            "transfer")

    def test_new_proposals(self):
        bts = self.bts
        p1 = bts.new_proposal()
        p2 = bts.new_proposal()
        self.assertIsNotNone(id(p1), id(p2))

    def test_new_txs(self):
        bts = self.bts
        p1 = bts.new_tx()
        p2 = bts.new_tx()
        self.assertIsNotNone(id(p1), id(p2))
Example #11
0
def tapbasic(referrer):

    # test is request has 'account' key
    if not request.json or 'account' not in request.json:
        abort(400)
    account = request.json.get('account', {})

    # make sure all keys are present
    if any([key not in account
            for key in ["active_key", "memo_key", "owner_key", "name"]]):
        abort(400)

    # prevent massive account registration
    if request.headers.get('X-Real-IP'):
        ip = request.headers.get('X-Real-IP')
    else:
        ip = request.remote_addr
    if ip != "127.0.0.1" and models.Accounts.exists(ip):
        return api_error("Only one account per IP")

    # Check if account name is cheap name
    if (not re.search(r"[0-9-]", account["name"]) and
            re.search(r"[aeiouy]", account["name"])):
        return api_error("Only cheap names allowed!")

    # This is not really needed but added to keep API-compatibility with Rails Faucet
    account.update({"id": None})

    transnet = Transnet(
        config.witness_url,
        nobroadcast=config.nobroadcast,
        keys=[config.wif]
    )

    try:
        Account(account["name"], transnet_instance=transnet)
        return api_error("Account exists")
    except:
        pass

    # Registrar
    registrar = account.get("registrar", config.registrar) or config.registrar
    try:
        registrar = Account(registrar, transnet_instance=transnet)
    except:
        return api_error("Unknown registrar: %s" % registrar)

    # Referrer
    referrer = account.get("referrer", config.default_referrer) or config.default_referrer
    try:
        referrer = Account(referrer, transnet_instance=transnet)
    except:
        return api_error("Unknown referrer: %s" % referrer)
    referrer_percent = account.get("referrer_percent", config.referrer_percent)

    # Create new account
    try:
        transnet.create_account(
            account["name"],
            registrar=registrar["id"],
            referrer=referrer["id"],
            referrer_percent=referrer_percent,
            owner_key=account["owner_key"],
            active_key=account["active_key"],
            memo_key=account["memo_key"],
            proxy_account=config.get("proxy", None),
            additional_owner_accounts=config.get("additional_owner_accounts", []),
            additional_active_accounts=config.get("additional_active_accounts", []),
            additional_owner_keys=config.get("additional_owner_keys", []),
            additional_active_keys=config.get("additional_active_keys", []),
        )
    except Exception as e:
        log.error(traceback.format_exc())
        return api_error(str(e))

    models.Accounts(account["name"], ip)

    balance = registrar.balance(config.core_asset)
    if balance and balance.amount < config.balance_mailthreshold:
        log.critical(
            "The faucet's balances is below {}".format(
                config.balance_mailthreshold
            ),
        )

    return jsonify({"account": {
        "name": account["name"],
        "owner_key": account["owner_key"],
        "active_key": account["active_key"],
        "memo_key": account["memo_key"],
        "referrer": referrer["name"]
    }})
class Testcases(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.bts = Transnet("wss://node.testnet.transnet.eu",
                            nobroadcast=True,
                            keys={"active": wif})
        set_shared_transnet_instance(self.bts)
        self.bts.set_default_account("init0")

    def test_add_one_proposal_one_op(self):
        bts = self.bts
        tx1 = bts.new_tx()
        proposal1 = bts.new_proposal(tx1, proposer="init0")
        op = operations.Transfer(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "from": "1.2.0",
                "to": "1.2.0",
                "amount": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "prefix": "TEST"
            })
        proposal1.appendOps(op)
        tx = tx1.json()
        self.assertEqual(tx["operations"][0][0], 22)
        self.assertEqual(len(tx["operations"]), 1)
        ps = tx["operations"][0][1]
        self.assertEqual(len(ps["proposed_ops"]), 1)
        self.assertEqual(ps["proposed_ops"][0]["op"][0], 0)

    def test_add_one_proposal_two_ops(self):
        bts = self.bts
        tx1 = bts.new_tx()
        proposal1 = bts.new_proposal(tx1, proposer="init0")
        op = operations.Transfer(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "from": "1.2.0",
                "to": "1.2.0",
                "amount": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "prefix": "TEST"
            })
        proposal1.appendOps(op)
        proposal1.appendOps(op)
        tx = tx1.json()
        self.assertEqual(tx["operations"][0][0], 22)
        self.assertEqual(len(tx["operations"]), 1)
        ps = tx["operations"][0][1]
        self.assertEqual(len(ps["proposed_ops"]), 2)
        self.assertEqual(ps["proposed_ops"][0]["op"][0], 0)
        self.assertEqual(ps["proposed_ops"][1]["op"][0], 0)

    def test_have_two_proposals(self):
        bts = self.bts
        tx1 = bts.new_tx()

        # Proposal 1
        proposal1 = bts.new_proposal(tx1, proposer="init0")
        op = operations.Transfer(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "from": "1.2.0",
                "to": "1.2.0",
                "amount": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "prefix": "TEST"
            })
        for i in range(0, 3):
            proposal1.appendOps(op)

        # Proposal 1
        proposal2 = bts.new_proposal(tx1, proposer="init0")
        op = operations.Transfer(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "from": "1.2.0",
                "to": "1.2.0",
                "amount": {
                    "amount": 5555555,
                    "asset_id": "1.3.0"
                },
                "prefix": "TEST"
            })
        for i in range(0, 2):
            proposal2.appendOps(op)
        tx = tx1.json()

        self.assertEqual(len(tx["operations"]), 2)  # 2 proposals

        # Test proposal 1
        prop = tx["operations"][0]
        self.assertEqual(prop[0], 22)
        ps = prop[1]
        self.assertEqual(len(ps["proposed_ops"]), 3)
        for i in range(0, 3):
            self.assertEqual(ps["proposed_ops"][i]["op"][0], 0)

        # Test proposal 2
        prop = tx["operations"][1]
        self.assertEqual(prop[0], 22)
        ps = prop[1]
        self.assertEqual(len(ps["proposed_ops"]), 2)
        for i in range(0, 2):
            self.assertEqual(ps["proposed_ops"][i]["op"][0], 0)
Example #13
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.bts = Transnet(nobroadcast=True, )
        set_shared_transnet_instance(self.bts)
class Testcases(unittest.TestCase):

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

        self.bts = Transnet(
            "wss://node.testnet.transnet.eu",
            nobroadcast=True,
            keys={"active": wif, "owner": wif, "memo": wif},
        )
        # from getpass import getpass
        # self.trns.wallet.unlock(getpass())
        set_shared_transnet_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"])