Bitshares研究系列【问题集一】

in #bitshares8 years ago

在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<fc::ecc::private_key> 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<public_key_type> all_keys_for_account;
      std::vector<public_key_type> active_keys = account.active.get_keys();
      std::vector<public_key_type> 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并发送,调用流程:

  1. begin_builder_transaction
  2. add_operation_to_builder_transaction oid [opId, {operation}]
  3. set_fees_on_builder_transaction oid BTS
  4. 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<object_id_type>());

      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 的帖子,期待您能留言交流!

Sort:  

你好!请接受cn区点赞机器人 @cnbuddy 对你作为cn区一员的感谢。假如我的留言打扰到你,请回复“取消”。

请教一下,我发行了一个guess资产,是二元预测币,想通过报喂价的方式,开展竞猜。
我用命令行钱包,编了一个命令行,但是喂价无效,能不能帮忙看看应该怎么设置?
publish_asset_feed hisonchen0129 GUESS {"settlement_price": {"base": {"amount": 10000,"asset_id": "1.3.2771"},"quote": {"amount": 10000,"asset_id": "1.3.113"}},"maintenance_collateral_ratio": 1000,"maximum_short_squeeze_ratio":1100,"core_exchange_rate": {"base": {"amount": 10000,"asset_id": "1.3.2771"},"quote": {"amount": 10000,"asset_id": "1.3.113"}}} true

Coin Marketplace

STEEM 0.04
TRX 0.32
JST 0.084
BTC 61656.48
ETH 1593.99
USDT 1.00
SBD 0.47