id:BSN_2021
Public Account: BSN Research Institute
He Lailiang, Jujube Technology
Background: In March this year, the open consortium chain "China Mobile Chain" was adapted and launched in the blockchain service network (BSN[1]), attracting a large number of developers, and some developers raised some common problems
Purpose: This article is to let readers understand how to call the RPC interface on China Mobile Chain (based on EOS) to assemble transactions, sign, upload to the chain and query the results of the chain
Applicable objects: Applicable to developers of the BSN open consortium chain-China Mobile Chain (based on EOS)
1. Prepare
• You need to create a project and create an account with bsn[2] now, you can refer to: https://bsnbase.com/static/tmpFile/bzsc/openper/7-3-6.html
• The eos endpoint can be obtained: https://opbningxia.bsngate.com:18602/api/aecb28acfd154cfeb90d0b6a8ecab1e7/rpc
•eos account/contract address: helailiang14
• Purchase enough resources (cpu, net, ram) for the account
• Install EOSIO development environment: cleos and keosd need to be installed, please refer to: https://developers.eos.io/welcome/latest/getting-started-guide/local-development-environment/installing-eosio-binaries • Deploy eos contract : hello.cpp
#include <eosio/eosio.hpp>
#include <eosio/transaction.hpp>
using namespace eosio;
// 通过[[eosio::contract]]标注这个类是一个合约
class [[eosio::contract]] hello : public contract
{
public:
using contract::contract;
// 在构造函数进行表对象的实例化, 标准合约构造函数,receiver也就是我们的合约账号(一般情况下),code就是我们的action名称,ds就是数据流
// get_self() 合约所在的账号 get_code() 当前交易请求的action方法名 get_datastream() 当前数据流
hello(name receiver, name code, datastream<const char *> ds) : contract(receiver, code, ds), friend_table(get_self(), get_self().value)
{
}
// 用[[eosio::action]]标注这个方法是一个合约action就行
// 注意:action的名称要求符合name类型的规则
[[eosio::action]] void hi(name user)
{
print("Hello, ", user);
print("get_self,", get_self().value);
// print("get_code,", get_code().value);
uint32_t now = current_time_point().sec_since_epoch();
auto friend_itr = friend_table.find(user.value);
// 数据不存在
if (friend_itr == friend_table.end())
{
// 第一个参数就是内存使用的对象,第二个参数就是添加表对象时的委托方法。
friend_table.emplace(get_self(), [&](auto &f) {
f.friend_name = user;
f.visit_time = now;
});
}
else
{
// 第一个参数是传递需要修改的数据指针,第二个参数是内存使用的对象,第二个参数就是表对象修改时的委托方法
friend_table.modify(friend_itr, get_self(), [&](auto &f) {
f.visit_time = now;
});
}
}
[[eosio::action]] void nevermeet(name user)
{
print("Never see you again, ", user);
auto friend_itr = friend_table.find(user.value);
check(friend_itr != friend_table.end(), "I don't know who you are.");
// 只有一个参数,就是要删除的对象指针
friend_table.erase(friend_itr);
}
[[eosio::action]] void meetagain()
{
uint32_t now = current_time_point().sec_since_epoch();
auto time_idx = friend_table.get_index<"time"_n>();
auto last_meet_itr = time_idx.begin();
check(last_meet_itr != time_idx.end(), "I don't have a friend.");
time_idx.modify(last_meet_itr, get_self(), [&](auto &f) {
f.visit_time = now;
});
}
private:
// 定义一个结构体,然后用[[eosio::table]]标注这个结构体是一个合约表。在结构体里定义一个函数名primary_key,返回uint64_t类型,作为主键的定义
struct [[eosio::table]] my_friend
{
name friend_name;
uint64_t visit_time;
uint64_t primary_key() const { return friend_name.value; }
double by_secondary() const { return -visit_time; }
};
// 定义表名和查询索引 "friends"_n就是定义表名,所以使用了name类型,之后my_friend是表的结构类
typedef eosio::multi_index<"friends"_n, my_friend> friends;
friends friend_table;
};
2. RPC call process
1. Serialize transaction information from JSON format to BIN format string
curl -X POST 'https://opbningxia.bsngate.com:18602/api/{您的开放联盟链项目ID/rpc/v1/chain/abi_json_to_bin' \
-d '{
"code": "helailiang14",
"action": "hi",
"args": {
"user": "helloworld"
}
}'
------------------
return
{"binargs":"00408a97721aa36a"}
2. Obtain the latest block number
curl GET 'https://opbningxia.bsngate.com:18602/api/{您的开放联盟链项目ID/rpc/v1/chain/get_info'
------------------
return
{
"server_version":"11d35f0f",
"chain_id":"9b4c6015f8b73b2d7ee3ebd92d249a1aba06a614e9990dcf54f7cf2e3d5172e1",
"head_block_num":15134328,
"last_irreversible_block_num":15134262,
"last_irreversible_block_id":"00e6ee360b5e7680a526ddea45db1be15c4be2cd2389020688218fe765be6db7",
"head_block_id":"00e6ee7889523875a28284effecdd1199cc960adb14c14c36cd1bd52afed6824",
"head_block_time":"2022-04-27T09:08:08.500",
"head_block_producer":"prod.b",
"virtual_block_cpu_limit":200000000,
"virtual_block_net_limit":1048576000,
"block_cpu_limit":199900,
"block_net_limit":1048576,
"server_version_string":"v3af0a20",
"fork_db_head_block_num":15134328,
"fork_db_head_block_id":"00e6ee7889523875a28284effecdd1199cc960adb14c14c36cd1bd52afed6824",
"server_full_version_string":"v3af0a20",
"last_irreversible_block_time":"2022-04-27T09:07:35.500"
}
获取到head_block_num : 15134328
引用
获取head_block_id:00e6ee7889523875a28284effecdd1199cc960adb14c14c36cd1bd52afed6824
引用
获取chain_id: 9b4c6015f8b73b2d7ee3ebd92d249a1aba06a614e9990dcf54f7cf2e3d5172e1
3. Obtain block details according to the block number
curl -X POST 'https://opbningxia.bsngate.com:18602/api/{您的开放联盟链项目ID/rpc/v1/chain/get_block' \
-d '{
"block_num_or_id": "15130610"
}'
------------------
return
{
"timestamp": "2022-04-27T09:08:08.500",
"producer": "prod.b",
"confirmed": 0,
"previous": "00e6ee77f2655528739622d2c9235026d4f10138b9821e46ea35165cb086d12d",
"transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
"action_mroot": "665584b582b234bf58d3708b31da20e14d266713e3bc6ce79ea3187cc2ffa5a4",
"schedule_version": 2,
"new_producers": null,
"producer_signature": "SIG_K1_KiYCDLMgE6gE1nNqQQL2jEEF3VVd6iaspAePvvJMjKwgg2Yf6GiTYcznrkymAdtZUAUFh28N8r9RzX936cASKDB6JW6ga3",
"transactions": [],
"id": "00e6ee7889523875a28284effecdd1199cc960adb14c14c36cd1bd52afed6824",
"block_num": 15134328,
"ref_block_prefix": 4018438818
}
Obtained
timestamp
: 2022-04-27T09:08:08
4. Sign the transaction
Use the signature tool provided by EOSIO to implement signature: after starting keosd, the signature service will be provided
curl -X POST POST 'http://192.168.1.46:8800/v1/wallet/sign_transaction' \
-d '[
{
"expiration": "2022-04-27T10:08:08",
"ref_block_num": 61048,
"ref_block_prefix": 4018438818,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [
{
"account": "helailiang14",
"name": "hi",
"authorization": [
{
"actor": "helailiang14",
"permission": "active"
}
],
"data": "00408a97721aa36a"
}
],
"transaction_extensions": [],
"signatures": [],
"context_free_data": []
},
[
"EOS6F6PRkSaPyijTDBYskFbsxpGz53JMTFbEhua94fQEyf7pAMc7Y"
],
"9b4c6015f8b73b2d7ee3ebd92d249a1aba06a614e9990dcf54f7cf2e3d5172e1"
]'
------------------
return :
{
"expiration":"2022-04-27T10:08:08",
"ref_block_num":61048,
"ref_block_prefix":4018438818,
"max_net_usage_words":0,
"max_cpu_usage_ms":0,
"delay_sec":0,
"context_free_actions":[
],
"actions":[
{
"account":"helailiang14",
"name":"hi",
"authorization":[
{
"actor":"helailiang14",
"permission":"active"
}
],
"data":"00408a97721aa36a"
}
],
"transaction_extensions":[
],
"signatures":[
"SIG_K1_K2AzV2Pk4SP3PQhcdQ1bYgGZgr7PUUcJkAGowvncFV1ngrZufeCQpveAUBRYvNA5uyxFk2hKiot3Mu7FCW5rqqeoU5SVTo"
],
"context_free_data":[
]
}
•
expiration
Expiration time.timestamp
60 minutes will be added here .•
ref_block_num
: The head_block_id returned by the second step is in hexadecimal and the field intercepts the first eight and lower 4 digits to convert to decimal, ee78 ==> 61048•
ref_block_prefix
: The head_block_id returned by the second step is in hexadecimal and the field is intercepted from 16 to 24, and then the two bytes are reversed (a28284ef is reversed to ef8482a2) to decimal, ef8482a2 ==> 4018438818•
account
Contract name, that is, the account that deploys the contract•
name
The contract method to call.•
actor
The caller. signer• : the string
data
generated in the first stepbin
•
permission
the type of permissions used•
EOS6F6PRkSaPyijTDBYskFbsxpGz53JMTFbEhua94fQEyf7pAMc7Y
: The public key that signed this transaction. In fact, it is signed by the corresponding private key in the wallet•
9b4c6015f8b73b2d7ee3ebd92d249a1aba06a614e9990dcf54f7cf2e3d5172e1
: is the chain_id obtained in the second step•
signatures
: signature resultSIG_K1_K2AzV2Pk4SP3PQhcdQ1bYgGZgr7PUUcJkAGowvncFV1ngrZufeCQpveAUBRYvNA5uyxFk2hKiot3Mu7FCW5rqqeoU5SVTo
5. Package transaction
Use cleos convert pack_transaction
to convert transaction messages into packed format
cleos convert pack_transaction '{
"expiration":"2022-04-27T10:08:08",
"ref_block_num":61048,
"ref_block_prefix":4018438818,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [
{
"account": "helailiang14",
"name": "hi",
"authorization": [
{
"actor": "helailiang14",
"permission": "active"
}
],
"data": "00408a97721aa36a"
}
],
"transaction_extensions": []
}'
------------------
return:
{
"signatures": [],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "0816696278eea28284ef000000000140029bc64567a26a000000000000806b0140029bc64567a26a00000000a8ed32320800408a97721aa36a00"
}
packed_trx
: Packed format of the transaction message
6. Submit the transaction
curl -X POST 'https://opbningxia.bsngate.com:18602/api/{您的开放联盟链项目ID/rpc/v1/chain/push_transaction' \
-d '{
"signatures": [
"SIG_K1_K2AzV2Pk4SP3PQhcdQ1bYgGZgr7PUUcJkAGowvncFV1ngrZufeCQpveAUBRYvNA5uyxFk2hKiot3Mu7FCW5rqqeoU5SVTo"
],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "0816696278eea28284ef000000000140029bc64567a26a000000000000806b0140029bc64567a26a00000000a8ed32320800408a97721aa36a00"
}'
------------------
return:
{
"transaction_id":"a69d03f6b1bab4bd8908124eef5e59d3e47df4063e697a07487308cde63a9f79",
"processed":{
"id":"a69d03f6b1bab4bd8908124eef5e59d3e47df4063e697a07487308cde63a9f79",
"block_num":15136664,
"block_time":"2022-04-27T09:27:36.500",
"producer_block_id":null,
"receipt":{
"status":"executed",
"cpu_usage_us":272,
"net_usage_words":13
},
"elapsed":272,
"net_usage":104,
"scheduled":false,
"action_traces":[
{
"action_ordinal":1,
"creator_action_ordinal":0,
"closest_unnotified_ancestor_action_ordinal":0,
"receipt":{
"receiver":"helailiang14",
"act_digest":"31ff1ecb2b0b0c89911b74c7930f08ecfefbd24ba59ef30a905d44068d2d8910",
"global_sequence":15199315,
"recv_sequence":2,
"auth_sequence":[
[
"helailiang14",
4
]
],
"code_sequence":1,
"abi_sequence":1
},
"receiver":"helailiang14",
"act":{
"account":"helailiang14",
"name":"hi",
"authorization":[
{
"actor":"helailiang14",
"permission":"active"
}
],
"data":{
"user":"helloworld"
},
"hex_data":"00408a97721aa36a"
},
"context_free":false,
"elapsed":63,
"console":"Hello, helloworldget_self,7683817463629939264",
"trx_id":"a69d03f6b1bab4bd8908124eef5e59d3e47df4063e697a07487308cde63a9f79",
"block_num":15136664,
"block_time":"2022-04-27T09:27:36.500",
"producer_block_id":null,
"account_ram_deltas":[
],
"account_disk_deltas":[
],
"except":null,
"error_code":null,
"return_value_hex_data":"",
"inline_traces":[
]
}
],
"account_ram_delta":null,
"except":null,
"error_code":null
}
}
signatures
: result of signing for step 4
packed_trx
: is the message conversion result of step 5
7. Query table data
curl -X POST 'https://opbningxia.bsngate.com:18602/api/{您的开放联盟链项目ID/rpc/v1/chain/get_table_rows' \
-d'{
"code": "helailiang14",
"table": "friends",
"scope": "helailiang14",
"json": true
}'
------------------
return:
{
"rows":[
{
"friend_name":"helloworld",
"visit_time":1651051656
}
],
"more":false,
"next_key":"",
"next_key_bytes":""
}
The data [helloworld] has been written into the table
References
[1]
BSN: https://bsnbase.com/[2]
bsn: https://bsnbase.com/p/home/Openalliance/projectManagement