比特股教程实时更细

Bitshares研究系列【问题集一】

2018-05-31  本文已影响58人  聂怀远

https://steemit.com/bitshares/@chaimyu/34sykz-bitshares

1. import_key时失败帐户数据也会加入钱包,用list_my_accounts能查到数据?

2.怎么发送operation?

3. 没有提供api的operation怎么发送?

4. faucet.yml配置url和port不生效

5. python-faucet怎么输出调试日志?

6. nathan、init0等帐号怎么生成的?

7. bitshares的chainid是什么?

在bitshares学习过程中,有一些零散问题整理在一块,互相之间并不一定存在关联性,计划每几个问题做一集发表。

1. import_key时失败帐户数据也会加入钱包,用list_my_accounts能查到数据?

例如公网引入"nathan"帐号

Chaim:cli_wallet Chaim$ ./cli_wallet --server-rpc-endpoint=wss://bitshares.dacplay.org/ws

Logging RPC to file: logs/rpc/rpc.log

1125691ms th_a      main.cpp:136                  main                ] key_to_wif( committee_private_key ): 5KCBDTcyDqzsqehcb52tW5nU6pXife6V2rX9Yf7c3saYSzbDZ5W

1125692ms th_a      main.cpp:140                  main                ] nathan_pub_key: BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

1125692ms th_a      main.cpp:141                  main                ] key_to_wif( nathan_private_key ): 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

Starting a new wallet with chain ID 4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8 (from egenesis)

1125692ms th_a      main.cpp:188                  main                ] wdata.ws_server: wss://bitshares.dacplay.org/ws

1125918ms th_a      main.cpp:193                  main                ] wdata.ws_user:  wdata.ws_password: 

Please use the set_password method to initialize a new wallet before continuing

new >>> set_password 123456

set_password 123456

null

locked >>> unlock 123456

unlock 123456

null

unlocked >>> import_key nathan 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

import_key nathan 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

false

unlocked >>> list_my_accounts

list_my_accounts

[{

    "id": "1.2.298",

    "membership_expiration_date": "1969-12-31T23:59:59",

    ...

}

]

查看import_key源码

  bool import_key(string account_name_or_id, string wif_key)

  {

      fc::optional optional_private_key = wif_to_key(wif_key);

      if (!optional_private_key)

        FC_THROW("Invalid private key");

      graphene::chain::public_key_type wif_pub_key = optional_private_key->get_public_key();

      account_object account = get_account( account_name_or_id );

      // make a list of all current public keys for the named account

      flat_set all_keys_for_account;

      std::vector active_keys = account.active.get_keys();

      std::vector owner_keys = account.owner.get_keys();

      std::copy(active_keys.begin(), active_keys.end(), std::inserter(all_keys_for_account, all_keys_for_account.end()));

      std::copy(owner_keys.begin(), owner_keys.end(), std::inserter(all_keys_for_account, all_keys_for_account.end()));

      all_keys_for_account.insert(account.options.memo_key);

      _keys[wif_pub_key] = wif_key;

      _wallet.update_account(account);

      _wallet.extra_keys[account.id].insert(wif_pub_key);

      return all_keys_for_account.find(wif_pub_key) != all_keys_for_account.end();

  }

此函数先根据wif_key取得公钥wif_pub_key,然后取得帐户的active key和owner key并加入all_keys_for_account中,函数返回结果是看wif_pub_key是否在all_keys_for_account中。

如果公网"nathan"帐户取的公钥是不对的,但 _wallet.update_account(account) 仍会把帐户信息加入本地钱包中。

2.怎么发送operation?

很多operation会提供对应的api函数,例如喂价api:

                      signed_transaction publish_asset_feed(string publishing_account, string symbol, price_feed feed, bool broadcast)

而operation的json数据格式可以用 get_prototype_operation 取得:

unlocked >>> get_prototype_operation asset_publish_feed_operation

get_prototype_operation asset_publish_feed_operation

[

  19,{

    "fee": {

      "amount": 0,

      "asset_id": "1.3.0"

    },

    "publisher": "1.2.0",

    "asset_id": "1.3.0",

    "feed": {

      "settlement_price": {

        "base": {

          "amount": 0,

          "asset_id": "1.3.0"

        },

        "quote": {

          "amount": 0,

          "asset_id": "1.3.0"

        }

      },

      "maintenance_collateral_ratio": 1750,

      "maximum_short_squeeze_ratio": 1500,

      "core_exchange_rate": {

        "base": {

          "amount": 0,

          "asset_id": "1.3.0"

        },

        "quote": {

          "amount": 0,

          "asset_id": "1.3.0"

        }

      }

    },

    "extensions": []

  }

]

很多operation都会有很多参数,例如以上发布喂价,就需要指定一个json格式的参数price_feed,而这个参数格式就是operation参数中,去掉operation id,去掉api已传参数的json格式即可,所以发布喂价的这个price_feed类似如下:

{"settlement_price": {"base": {"amount": 25,"asset_id": "1.3.1"},"quote": {"amount": 63647,"asset_id": "1.3.0"}},"maintenance_collateral_ratio": 1750,"maximum_short_squeeze_ratio":1100,"core_exchange_rate": {"base": {"amount": 25,"asset_id": "1.3.1"},"quote": {"amount": 66829,"asset_id": "1.3.0"}}}

3. 没有提供api的operation怎么发送?

可以手动构造operation并发送,调用流程:

begin_builder_transaction

add_operation_to_builder_transaction oid [opId, {operation}]

set_fees_on_builder_transaction oid BTS

sign_builder_transaction oid true

operation id参见bitshares研究系列【operation的实现】

手动构造transfer operation数据并发送交易,按如下操作:

先查看operation格式,以下构造operation时需要使用其中部分数据

unlocked >>> get_prototype_operation transfer_operation

get_prototype_operation transfer_operation

[

  0,{

    "fee": {

      "amount": 0,

      "asset_id": "1.3.0"

    },

    "from": "1.2.0",

    "to": "1.2.0",

    "amount": {

      "amount": 0,

      "asset_id": "1.3.0"

    },

    "extensions": []

  }

]

unlocked >>> list_account_balances barnard18

list_account_balances barnard18

6.85982 BTS

unlocked >>> begin_builder_transaction

begin_builder_transaction

0

unlocked >>> add_operation_to_builder_transaction 0 [0,{"from": "1.2.861586", "to": "1.2.879822", "amount": {"amount": 100000, "asset_id": "1.3.0"}}]

add_operation_to_builder_transaction 0 [0,{"from": "1.2.861586", "to": "1.2.879822", "amount": {"amount": 100000, "asset_id": "1.3.0"}}]

null

unlocked >>> set_fees_on_builder_transaction 0 BTS

set_fees_on_builder_transaction 0 BTS

{

  "amount": 10420,

  "asset_id": "1.3.0"

}

unlocked >>> sign_builder_transaction 0 true

sign_builder_transaction 0 true

{

  "ref_block_num": 54238,

  "ref_block_prefix": 2893069574,

  "expiration": "2018-05-08T07:47:03",

  "operations": [[

      0,{

        "fee": {

          "amount": 10420,

          "asset_id": "1.3.0"

        },

        "from": "1.2.861586",

        "to": "1.2.879822",

        "amount": {

          "amount": 100000,

          "asset_id": "1.3.0"

        },

        "extensions": []

      }

    ]

  ],

  "extensions": [],

  "signatures": [

    "1f40a75c45c544217e4af6a8ecae8e04f21d7adad7db91460284debfc52736a9797b5ee906dce9eed0ae47a4ee7c2f5f3532174fe64852c7e93a8469f09ac76b5a"

  ]

}

unlocked >>> list_account_balances barnard18

list_account_balances barnard18

5.75562 BTS

operation需要import_key保证有私钥和权限

4. faucet.yml配置url和port不生效

配了也是监听localhost:3000

=> Rails 4.2.4 application starting in development on http://localhost:3000

没具体去查原因,直接启动时指定监听地址和端口

bash-3.2$ rails s -b 0.0.0.0 -p 3000

5. python-faucet怎么输出调试日志?

在用python-faucet时详细日志看不到,而运行又出现问题,查看graphene这些库都用的是logging

在manage.py中增加以下语句:

import logging

logging.basicConfig(level=logging.DEBUG)

这样就能打出所有调试信息了,同时也可以在这通过filename参数指定日志文件。

6. nathan、init0等帐号怎么生成的?

我们知道bitshares里有一些帐号,例如nathan、init0等,也知道这些帐号是内置的,但是怎么内置进去的呢?

在创世区块时需要指定genesis.json文件,可以用以下方式生成一个例子文件:

./witness_node --create-genesis-json my-genesis.json

文件中指定了nathan、init0等帐户的公私钥信息:

  "initial_accounts": [{

      "name": "init0",

      "owner_key": "BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",

      "active_key": "BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",

      "is_lifetime_member": true

    },

    ...

    {

      "name": "nathan",

      "owner_key": "BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",

      "active_key": "BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",

      "is_lifetime_member": false

    }

  ]

在db_init.cpp中有初始化数据库的操作,其中对初始帐户的操作如下:

void database::init_genesis(const genesis_state_type& genesis_state)

{

  ...

  // Create initial accounts

  for( const auto& account : genesis_state.initial_accounts )

  {

      account_create_operation cop;

      cop.name = account.name;

      cop.registrar = GRAPHENE_TEMP_ACCOUNT;

      cop.owner = authority(1, account.owner_key, 1);

      if( account.active_key == public_key_type() )

      {

        cop.active = cop.owner;

        cop.options.memo_key = account.owner_key;

      }

      else

      {

        cop.active = authority(1, account.active_key, 1);

        cop.options.memo_key = account.active_key;

      }

      account_id_type account_id(apply_operation(genesis_eval_state, cop).get());

      if( account.is_lifetime_member )

      {

          account_upgrade_operation op;

          op.account_to_upgrade = account_id;

          op.upgrade_to_lifetime_member = true;

          apply_operation(genesis_eval_state, op);

      }

  }

  ...

}

7. bitshares的chainid是什么?

使用cli_wallet等都可能需要指定chainid,而在bitshares-core修改时经常发现chainid变化了,什么原因呢?

在genesis.json中有个初始chainid,如下:

  "initial_chain_id": "aa34045518f1469a28fa4578240d5f039afa9959c0b95ce3b39674efa691fb21",

在application.cpp中有此函数:

      void startup()

      {

        ...

              if( modified_genesis )

              {

                  std::cerr << "WARNING:  GENESIS WAS MODIFIED, YOUR CHAIN ID MAY BE DIFFERENT\n";

                  genesis_str += "BOGUS";

                  genesis.initial_chain_id = fc::sha256::hash( genesis_str );

              }

              else

                  genesis.initial_chain_id = fc::sha256::hash( genesis_str );

        ...

      }       

其中针对genesis.json做了hash计算并得出chainid,也就是说genesis.json改了链id就变了,这也符合实际情况,创世区块一旦创建链id就确定了。

如果为了开发调试需要,当然可以把这个写成固定的链id,这样各方就不用变动了。

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

上一篇 下一篇

猜你喜欢

热点阅读