bitshares基本概念详解【密钥修改】

Words
957
Reading
5 min
8y
Listen to this post
~6 min

今天来了解下Bitshares怎么实现修改帐户密钥,还有帐户模式下怎么修改密码。

Bitshares钱包

Bitshares钱包提供修改密钥功能,可以对资金权限、帐户权限、备注密钥和帐号模式的密码进行修改,如下图:

“帐号模式”仅使用密码就能从任何地方(包括不同浏览器,不同的钱包提供网站)登录自己的账户,比较方便。在“帐号模式登录”中设置密码,密码至少要12位,在下方会生成资金密钥、帐户密钥、备注密钥,可以点击密钥右方的“使用”来确认哪个密钥有效,然后再点击上方“保存修改”,输入密码后才能修改完成。如下图:

再回“资金权限”项就可以看到,资金权限的公钥增加了一个,如下图:

可以看到通过Bitshares钱包,可以手动设置各个权限的公私钥,也可以修改帐号模式的密码,帐号模式的密码修改完成后原有密钥并不会删除,需要自己到权限页面中手动删除。

但是这个地方一定要注意几个事情:

  1. 别把密钥全移除了,如果是帐户权限全移除的话这个帐户就作废了;
  2. 权重/阈值想清楚了再设,一旦设错可能再也无法操作。

简单点说就是可以随便增加,但别随便删除和调整权重/阈值!

我一朋友就用多重签名把终身会员帐户给弄废了,因为设了必须两个帐户同意才能操作,而另一个帐户是别人的,但别人的密码密钥都没有了!当然我也有个帐户barnard19把自己的owner权限删除了,在owner权限中加上了另一帐号,不过这个应该还有点办法,等理清了再看看怎么恢复!

更详细权限说明传送门:Bitshares的权限参考和多重签名

密钥修改分析

密钥数据结构

get_account barnard20
{
  "id": "1.2.879822",
  "membership_expiration_date": "1970-01-01T00:00:00",
  "registrar": "1.2.450921",
  "referrer": "1.2.450921",
  "lifetime_referrer": "1.2.450921",
  "network_fee_percentage": 2000,
  "lifetime_referrer_fee_percentage": 3000,
  "referrer_rewards_percentage": 7000,
  "name": "barnard20",
  "owner": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [[
        "BTS5e9Mnf2n1ExHwZVWixJr3FS5VasZG9jNRB4Yh4mFFJuW7xHg1R",
        1
      ],[
        "BTS6psUtCCC3gg6xoDVemGGmAQta2cU8BTBQVFLwGHaQJTZjcP4s3",
        1
      ]
    ],
    "address_auths": []
  },
  "active": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [[
        "BTS8EdfKXbmNrzcngwZBZpUrTNotsFGFWTRKpNaBpcGRrx4Qrqcz6",
        1
      ],[
        "BTS6KarQcA5MYBBTJ6xHWqBx2r1XSKxYy6YXytM8T8MW5CTsV8agh",
        1
      ]
    ],
    "address_auths": []
  },
  "options": {
    "memo_key": "BTS8EdfKXbmNrzcngwZBZpUrTNotsFGFWTRKpNaBpcGRrx4Qrqcz6",
    "voting_account": "1.2.5",
    "num_witness": 0,
    "num_committee": 0,
    "votes": [],
    "extensions": []
  },

从以上json数据可以看到资金权限和帐户权限可以有3种不同的方式控制:帐号、密钥、地址,每种方式都可以有多个帐号/密钥/地址,而memo密钥只能有1个,这个是因为memo加密是要用双方公钥,多个memo密钥就乱了,见bitshares研究系列【memo加解密】

代码实现

密钥修改其实就是对帐号信息的修改,通过 account_update_operation 实现,如下:

void_result account_update_evaluator::do_apply( const account_update_operation& o )
{ try {
   database& d = db();
   bool sa_before, sa_after;
   d.modify( *acnt, [&](account_object& a){
      if( o.owner )
      {
         a.owner = *o.owner;
         a.top_n_control_flags = 0;
      }
      if( o.active )
      {
         a.active = *o.active;
         a.top_n_control_flags = 0;
      }
    ...
}

这个修改只是简单的赋值,取决于请求的数据。

bitshares钱包修改帐号密码是先增加密钥,需要用户再手动删除,从代码来看应该是可以删除和增加同时操作的,来试一下。

不过修改帐户密钥没有cli_wallet方法,只能直连节点发送operation命令来完成,用python-utransnet库,但只提供了allow、disallow方法,没有替换接口,增加一个changeallow,如下:

    def changeallow(
        self, foreign, changed, weight=None, permission="active",
        account=None, threshold=None, **kwargs
    ):
        """ Remove additional access to an account by some other public
            key or account.

            :param str foreign: The foreign account that will obtain access
            :param str permission: (optional) The actual permission to
                modify (defaults to ``active``)
            :param str account: (optional) the account to allow access
                to (defaults to ``default_account``)
            :param int threshold: The threshold that needs to be reached
                by signatures to be able to interact
        """
        if not account:
            if "default_account" in config:
                account = config["default_account"]
        if not account:
            raise ValueError("You need to provide an account")

        if permission not in ["owner", "active"]:
            raise ValueError(
                "Permission needs to be either 'owner', or 'active"
            )
        account = Account(account, transnet_instance=self)
        authority = account[permission]

        print("prefix:" + str(self.prefix))
        try:
            pubkey = PublicKey(foreign, prefix=self.prefix)
            print("foreign pubkey:" + str(pubkey))
            affected_items = list(
                filter(lambda x: x[0] == str(pubkey),
                       authority["key_auths"]))
            authority["key_auths"] = list(filter(
                lambda x: x[0] != str(pubkey),
                authority["key_auths"]
            ))
        except:
            try:
                foreign_account = Account(foreign, transnet_instance=self)
                affected_items = list(
                    filter(lambda x: x[0] == foreign_account["id"],
                           authority["account_auths"]))
                authority["account_auths"] = list(filter(
                    lambda x: x[0] != foreign_account["id"],
                    authority["account_auths"]
                ))
            except:
                raise ValueError(
                    "Unknown foreign account or unvalid public key"
                )

        if not affected_items:
            raise ValueError("Changes nothing!")
        removed_weight = affected_items[0][1]

        if not weight:
            weight = account[permission]["weight_threshold"]
        from copy import deepcopy
        authority = deepcopy(account[permission])
        try:
            pubkey = PublicKey(changed, prefix=self.prefix)
            authority["key_auths"].append([
                str(pubkey),
                weight
            ])
        except:
            try:
                foreign_account = Account(changed, transnet_instance=self)
                authority["account_auths"].append([
                    foreign_account["id"],
                    weight
                ])
            except:
                raise ValueError(
                    "Unknown foreign account or invalid public key"
                )


        # Define threshold
        if threshold:
            authority["weight_threshold"] = threshold

        # Correct threshold (at most by the amount removed from the
        # authority)
        try:
            self._test_weights_treshold(authority)
        except:
            log.critical(
                "The account's threshold will be reduced by %d"
                % (removed_weight)
            )
            authority["weight_threshold"] -= removed_weight
            self._test_weights_treshold(authority)

        op = operations.Account_update(**{
            "fee": {"amount": 0, "asset_id": "1.3.0"},
            "account": account["id"],
            permission: authority,
            "extensions": {}
        })
        if permission == "owner":
            return self.finalizeOp(op, account["name"], "owner", **kwargs)
        else:
            return self.finalizeOp(op, account["name"], "active", **kwargs)

调用方法:

r = transnet.changeallow("BTS6KarQcA5MYBBTJ6xHWqBx2r1XSKxYy6YXytM8T8MW5CTsV8agh", "BTS8EXUV2yr1VoSL1r3eDckbE4WB5K6o6YTKjiRK6Zyh6jXFaC7c8", account="barnard20")

执行成功,这样就把“BTS6KarQcA5MYBBTJ6xHWqBx2r1XSKxYy6YXytM8T8MW5CTsV8agh”替换成“BTS8EXUV2yr1VoSL1r3eDckbE4WB5K6o6YTKjiRK6Zyh6jXFaC7c8”了。

结论

帐户密码是可以直接替换的,能把增加、删除两步操作合到一块,除了增加响应速度,省那么一点燃料费之外,可能还有些其它用处!


感谢您阅读 chaimyu@chaimyu 的帖子,期待您能留言交流!