专题 - 交易
本专题用于描述交易相关的所有操作,包括:打包 (pack)、解包 (unpack)、签名 (sign)。同时,还包括交易中 action 的操作,比如:打包 (pack)、解包 (unpack)。
我们先构造一个交易,然后再来分析上述所有操作。这里我们利用工具 cleos 提供的返回交易信息的功能,这需要打开选项 --dont-broadcast。
构造交易样本
构造一个交易,并获得其 pack 后的结果。
通过选项 --json --dont-broadcast --return-packed 以 josn 的格式返回某个交易的 pack 结果。
$ cleos transfer eosio alice "1 EOS" "memo" --contract eosio.token --json --dont-broadcast --return-packed
{
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "443f395de032a6f77608000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232250000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f00"
}
当然,我们也可以不设置选项 --return-packed,这获得的是未 pack 的交易。
需要注意的是,上面的交易信息中已经包含签名信息。实际上 pack & unpack 操作并不会涉及到签名。签名也是对于 pack 后的二进制数据进行的,如通过命令 cleos sign。因此,我们在 pack & unpack 操作时可以不用传递签名相关信息,因为即使传递了也会被过滤掉。
1. unpack 一个交易
1.1 不带签名信息 & 不解包 actions 的详细
$ cleos convert unpack_transaction '{
"signatures": [
],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "443f395de032a6f77608000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232250000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f00"
}'
{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [],
"context_free_data": []
}
1.2 带签名信息 & 解包 actions 的详细
通过选项 --unpack-action-data 把交易中的 action 也解包出来。
$ cleos convert unpack_transaction '{
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "443f395de032a6f77608000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232250000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f00"
}' --unpack-action-data
{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": {
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
},
"hex_data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"context_free_data": []
}
2. pack 一个交易
2.1 不带签名信息 & 不带 action 详细信息
$ cleos convert pack_transaction '{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
],
"context_free_data": []
}'
{
"signatures": [],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "443f395de032a6f77608000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232250000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f00"
}
2.2 带签名信息 & 带 action 详细信息
如果交易中包含详细的 actions,需要打开选项 --pack-action-data,否则打包交易会失败。
$ cleos convert pack_transaction '{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": {
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
},
"hex_data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"context_free_data": []
}' --pack-action-data
{
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "443f395de032a6f77608000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232250000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f00"
}
3. unpack 一个 action
$ cleos convert unpack_action_data eosio.token transfer 0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f
{
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
}
其中:
- eosio.token 是合约账户
- transfer 是 action 名称
- 16 进制字符串是 packed_action_data。
4. pack 一个 action
$ cleos convert pack_action_data eosio.token transfer '{
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
}'
0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f
其中:
- eosio.token 是合约账户
- transfer 是 action 名称
- 16 进制字符串是 packed_action_data。
5. 获取交易 id
$ cleos get transaction_id '{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
],
"context_free_data": []
}'
bf2434cf3ab87418e201a2d7e4526b10fbbb0cb2ad15bd6b7000551e6cd2a9cc
6. 交易签名
$ cleos sign '{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
],
"context_free_data": []
}' --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
info 2019-07-25T07:29:14.372 thread-0 main.cpp:3261 operator() ] grabbing chain_id from nodeos
{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"context_free_data": []
}
注意,--chain-id 如果不设置,需要通过和 nodeos 交互获得。同时,考虑安全,私钥也不要通过选项 --private-key 传递。
打开选项 --push-transaction 将交易发送到链上。注意,这需要将字段 expiration 设置正确。这也就说明了,签名时有些字段并不会被包含进来,如字段 expiration。
$ cleos sign '{
"expiration": "2019-07-25T09:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
],
"context_free_data": []
}' --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 --push-transaction
info 2019-07-25T08:36:07.424 thread-0 main.cpp:3261 operator() ] grabbing chain_id from nodeos
{
"transaction_id": "ea822206ce3f901ed91013d1fc18fe48e7b1f0fcccdb172bde1efdf32fa1a70d",
"processed": {
"id": "ea822206ce3f901ed91013d1fc18fe48e7b1f0fcccdb172bde1efdf32fa1a70d",
"block_num": 34948,
"block_time": "2019-07-25T08:36:07.500",
"producer_block_id": null,
"receipt": {
"status": "executed",
"cpu_usage_us": 346,
"net_usage_words": 17
},
"elapsed": 346,
"net_usage": 136,
"scheduled": false,
"action_traces": [{
"receipt": {
"receiver": "eosio.token",
"act_digest": "0417de465219905a54882b499a0a1e4835d1487fadaee214cedaec750f1e50c4",
"global_sequence": 35130,
"recv_sequence": 45,
"auth_sequence": [[
"eosio",
35101
]
],
"code_sequence": 1,
"abi_sequence": 1
},
"act": {
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": {
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
},
"hex_data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
},
"context_free": false,
"elapsed": 195,
"console": "",
"trx_id": "ea822206ce3f901ed91013d1fc18fe48e7b1f0fcccdb172bde1efdf32fa1a70d",
"block_num": 34948,
"block_time": "2019-07-25T08:36:07.500",
"producer_block_id": null,
"account_ram_deltas": [{
"account": "eosio",
"delta": 240
}
],
"except": null,
"inline_traces": [{
"receipt": {
"receiver": "eosio",
"act_digest": "0417de465219905a54882b499a0a1e4835d1487fadaee214cedaec750f1e50c4",
"global_sequence": 35131,
"recv_sequence": 35044,
"auth_sequence": [[
"eosio",
35102
]
],
"code_sequence": 1,
"abi_sequence": 1
},
"act": {
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": {
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
},
"hex_data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
},
"context_free": false,
"elapsed": 12,
"console": "",
"trx_id": "ea822206ce3f901ed91013d1fc18fe48e7b1f0fcccdb172bde1efdf32fa1a70d",
"block_num": 34948,
"block_time": "2019-07-25T08:36:07.500",
"producer_block_id": null,
"account_ram_deltas": [],
"except": null,
"inline_traces": []
},{
"receipt": {
"receiver": "alice",
"act_digest": "0417de465219905a54882b499a0a1e4835d1487fadaee214cedaec750f1e50c4",
"global_sequence": 35132,
"recv_sequence": 1,
"auth_sequence": [[
"eosio",
35103
]
],
"code_sequence": 1,
"abi_sequence": 1
},
"act": {
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": {
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
},
"hex_data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
},
"context_free": false,
"elapsed": 8,
"console": "",
"trx_id": "ea822206ce3f901ed91013d1fc18fe48e7b1f0fcccdb172bde1efdf32fa1a70d",
"block_num": 34948,
"block_time": "2019-07-25T08:36:07.500",
"producer_block_id": null,
"account_ram_deltas": [],
"except": null,
"inline_traces": []
}
]
}
],
"except": null
}
}
附录 1. unpacked action
一个未打包的 action 结构。
{
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
}
附录 2. packed action
一个 action 打包后的数据格式。
0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f
附录 3. unpacked transaction
3.1 不带签名信息 & 不带 action 详细信息
{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
],
"context_free_data": []
}
3.2 带签名信息 & 带 action 详细信息
包含详细的 actions。
{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": {
"from": "eosio",
"to": "alice",
"quantity": "1.0000 EOS",
"memo": "memo"
},
"hex_data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"context_free_data": []
}
需要注意的是,交易哈希是不包含签名信息的。测试结果如下:
$ cleos get transaction_id '{
"expiration": "2019-07-25T05:33:56",
"ref_block_num": 13024,
"ref_block_prefix": 142014374,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "transfer",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"context_free_data": []
}'
bf2434cf3ab87418e201a2d7e4526b10fbbb0cb2ad15bd6b7000551e6cd2a9cc
附录 4. packed transaction
4.1 不带签名信息
{
"signatures": [
],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "443f395de032a6f77608000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232250000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f00"
}
甚至,整个字段 signatures 都可以去掉。
4.2 带签名信息
{
"signatures": [
"SIG_K1_KX2SPX8cqDheFKgSSVDZwiwqP98uJVVJ4SLA8Pp3Kf6QEtGUgxNHhWGkgU18JEsbnngij1udE5t9NfMFkmAPa4ZQS4K4JR"
],
"compression": "none",
"packed_context_free_data": "",
"packed_trx": "443f395de032a6f77608000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232250000000000ea30550000000000855c34102700000000000004454f5300000000046d656d6f00"
}
项目源代码
项目源代码会逐步上传到 Github,地址为 https://github.com/windstamp/blockchain。
Contributor
- Windstamp, https://github.com/windstamp