EOS のスマートコントラクトを開発する時、_code
と _self
について把握できてなかったので、この辺の内容を調べてみました。
変数 | 英語 | 日本語(意訳) |
---|---|---|
_code | The name of this contract | このコントラクトの名前 |
_self | The code name of the action this contract is processing. | この契約が処理しているアクションのコード名 |
出典:https://eosio.github.io/eosio.cdt/group__contract.html#variable-self
先に結論
-
_self
は、どのケースでも関数が所属しているコントラクトになる -
_code
は、-
require_recipient
の通知を受け取る場合だけ、通知元のコントラクトになる - それ以外は、
_self
と同じ
-
require_recipient 以外、プリントアウトしてみる
-
hello
コントラクト関数内 -
hello
コントラクトがinline action
で呼び出したmessage
コントラクトの関数内 -
hello
コントラクトがdeferred action
で呼び出したmessage
コントラクトの関数内
hello.cpp
#include <eosiolib/eosio.hpp>
#include <eosiolib/transaction.hpp>
using namespace eosio;
class [[eosio::contract]] hello : public eosio::contract {
public:
hello(name receiver, name code, datastream<const char *> ds) : contract(receiver, code, ds){}
[[eosio::action]]
void hi(name from) {
print("_code : ", name{_code}, ", _self : ", name{_self}, ", get_code: ", name{get_code()}, ", get_self : ", name{get_self()});
action(
permission_level{from, "active"_n},
"message"_n,
"callme"_n,
std::make_tuple()
).send();
transaction txn{};
const uint128_t sender_id = 100; // 遅延呼び出しに付ける任意の id
txn.actions.emplace_back(
action(
permission_level{from, "active"_n},
"message"_n,
"callme"_n,
std::make_tuple()
)
);
txn.delay_sec = 1; // 遅延する秒数
txn.send(sender_id, from);
}
};
EOSIO_DISPATCH(hello, (hi))
message.cpp
#include <eosiolib/eosio.hpp>
using namespace eosio;
class [[eosio::contract]] message : public eosio::contract
{
public:
message(name receiver, name code, datastream<const char *> ds) : contract(receiver, code, ds){}
[[eosio::action]]
void callme()
{
print("_code : ", name{_code}, ", _self : ", name{_self}, ", get_code: ", name{get_code()}, ", get_self : ", name{get_self()});
}
};
EOSIO_DISPATCH(message, (callme))
実験
上記2つコントラクトをコンパイルしてデプロイしておいてから、実行してみると
cleos push action hello hi '["bob"]' -p bob
executed transaction: 84f5772661416e48c86cea7cc087bd23188de33afe5564cb455a24d2f69c29d4 144 bytes 6513 us
# hello <= hello::hi {"from":"bob"}
>> _code : hello, _self : hello, get_code: hello, get_self : hello
# message <= message::callme ""
>> _code : message, _self : message, get_code: message, get_self : message
warning: transaction executed locally, but may not be confirmed by the network yet ]
nodes
側のログで確認すると、
2018-12-10T20:43:50.169427100Z debug 2018-12-10T20:43:50.167 thread-0 apply_context.cpp:28 print_debug ]
2018-12-10T20:43:50.169460900Z [(hello,hi)->hello]: CONSOLE OUTPUT BEGIN =====================
2018-12-10T20:43:50.169480500Z _code : hello, _self : hello, get_code: hello, get_self : hello
2018-12-10T20:43:50.169502300Z [(hello,hi)->hello]: CONSOLE OUTPUT END =====================
2018-12-10T20:43:50.169551700Z debug 2018-12-10T20:43:50.167 thread-0 apply_context.cpp:28 print_debug ]
2018-12-10T20:43:50.169573200Z [(message,callme)->message]: CONSOLE OUTPUT BEGIN =====================
2018-12-10T20:43:50.169593800Z _code : message, _self : message, get_code: message, get_self : message
2018-12-10T20:43:50.169625700Z [(message,callme)->message]: CONSOLE OUTPUT END =====================
2018-12-10T20:43:50.506156600Z info 2018-12-10T20:43:50.502 thread-0 producer_plugin.cpp:1490 produce_block ] Produced block 001432f1eb282355... #1323761 @ 2018-12-10T20:43:50.500 signed b
y eosio [trxs: 1, lib: 1323760, confirmed: 0]
2018-12-10T20:43:51.010081600Z info 2018-12-10T20:43:51.001 thread-0 producer_plugin.cpp:1490 produce_block ] Produced block 001432f2192708e3... #1323762 @ 2018-12-10T20:43:51.000 signed b
y eosio [trxs: 0, lib: 1323761, confirmed: 0]
2018-12-10T20:43:51.011983000Z debug 2018-12-10T20:43:51.011 thread-0 apply_context.cpp:28 print_debug ]
2018-12-10T20:43:51.012076700Z [(message,callme)->message]: CONSOLE OUTPUT BEGIN =====================
2018-12-10T20:43:51.012197000Z _code : message, _self : message, get_code: message, get_self : message
2018-12-10T20:43:51.012250300Z [(message,callme)->message]: CONSOLE OUTPUT END =====================
結論
_code
と _self
は、どのケースでも同じ値でした
require_recipient で通知された場合
hello.cpp
hi
関数の処理に require_recipient("message"_n);
を追記し、message
アカウントに通知する
#include <eosiolib/eosio.hpp>
#include <eosiolib/transaction.hpp>
using namespace eosio;
class [[eosio::contract]] hello : public eosio::contract {
public:
hello(name receiver, name code, datastream<const char *> ds) : contract(receiver, code, ds){}
[[eosio::action]]
void hi(name from) {
print("_code : ", name{_code}, ", _self : ", name{_self}, ", get_code: ", name{get_code()}, ", get_self : ", name{get_self()});
require_recipient("message"_n);
action(
permission_level{from, "active"_n},
"message"_n,
"callme"_n,
std::make_tuple()
).send();
transaction txn{};
const uint128_t sender_id = 100; // 遅延呼び出しに付ける任意の id
txn.actions.emplace_back(
action(
permission_level{from, "active"_n},
"message"_n,
"callme"_n,
std::make_tuple()
)
);
txn.delay_sec = 1; // 遅延する秒数
txn.send(sender_id, from);
}
};
EOSIO_DISPATCH(hello, (hi))
message.cpp
-
EOSIO_DISPATCH_EX
を定義し、通知受け取った時の処理を変更して、hello
からの通知を受け取るようにします。 -
hi
メソッドも定義して、プリントアウトしています。
#include <eosiolib/eosio.hpp>
using namespace eosio;
class [[eosio::contract]] message : public eosio::contract
{
public:
message(name receiver, name code, datastream<const char *> ds) : contract(receiver, code, ds){}
[[eosio::action]]
void callme()
{
print("_code : ", name{_code}, ", _self : ", name{_self}, ", get_code: ", name{get_code()}, ", get_self : ", name{get_self()});
}
[[eosio::action]]
void hi()
{
print("_code : ", name{_code}, ", _self : ", name{_self}, ", get_code: ", name{get_code()}, ", get_self : ", name{get_self()});
}
};
#define EOSIO_DISPATCH_EX(TYPE, MEMBERS) \
extern "C" \
{ \
void apply(uint64_t receiver, uint64_t code, uint64_t action) \
{ \
print("receiver : ", name{receiver}, ", code : ", name{code}); \
if (code == receiver || code == "hello"_n.value) \
{ \
switch (action) \
{ \
EOSIO_DISPATCH_HELPER(TYPE, MEMBERS) \
} \
/* does not allow destructor of thiscontract to run: eosio_exit(0); */ \
} \
} \
}
EOSIO_DISPATCH_EX(message, (callme)(hi))
実行すると、
cleos push action hello hi '["bob"]' -p bob
executed transaction: 03ff84d534bf1c7f84ab6296ef78d91673df944035ea6b8a145bde481f5f33f5 144 bytes 6008 us
# hello <= hello::hi {"from":"bob"}
>> _code : hello, _self : hello, get_code: hello, get_self : hello
# message <= hello::hi {"from":"bob"}
>> receiver : message, code : hello_code : hello, _self : message, get_code: hello, get_self : message
# message <= message::callme ""
>> receiver : message, code : message_code : message, _self : message, get_code: message, get_self : message
warning: transaction executed locally, but may not be confirmed by the network yet ]
nodes
側のログは、下記のようになっています
2018-12-10T21:16:14.414101400Z debug 2018-12-10T21:16:14.411 thread-0 apply_context.cpp:28 print_debug ]
2018-12-10T21:16:14.414181300Z [(hello,hi)->hello]: CONSOLE OUTPUT BEGIN =====================
2018-12-10T21:16:14.414208800Z _code : hello, _self : hello, get_code: hello, get_self : hello
2018-12-10T21:16:14.414260700Z [(hello,hi)->hello]: CONSOLE OUTPUT END =====================
2018-12-10T21:16:14.414308700Z debug 2018-12-10T21:16:14.412 thread-0 apply_context.cpp:28 print_debug ]
2018-12-10T21:16:14.414331600Z [(hello,hi)->message]: CONSOLE OUTPUT BEGIN =====================
2018-12-10T21:16:14.414360900Z receiver : message, code : hello_code : hello, _self : message, get_code: hello, get_self : message
2018-12-10T21:16:14.414388000Z [(hello,hi)->message]: CONSOLE OUTPUT END =====================
2018-12-10T21:16:14.414424300Z debug 2018-12-10T21:16:14.412 thread-0 apply_context.cpp:28 print_debug ]
2018-12-10T21:16:14.414446100Z [(message,callme)->message]: CONSOLE OUTPUT BEGIN =====================
2018-12-10T21:16:14.414465500Z receiver : message, code : message_code : message, _self : message, get_code: message, get_self : message
2018-12-10T21:16:14.414489100Z [(message,callme)->message]: CONSOLE OUTPUT END =====================
2018-12-10T21:16:14.508502900Z info 2018-12-10T21:16:14.505 thread-0 producer_plugin.cpp:1490 produce_block ] Produced block 0014421cffd84734... #1327644 @ 2018-12-10T21:16:14.500 signed b
y eosio [trxs: 1, lib: 1327643, confirmed: 0]
2018-12-10T21:16:15.012995300Z info 2018-12-10T21:16:15.002 thread-0 producer_plugin.cpp:1490 produce_block ] Produced block 0014421ddfdb1fdc... #1327645 @ 2018-12-10T21:16:15.000 signed b
y eosio [trxs: 0, lib: 1327644, confirmed: 0]
2018-12-10T21:16:15.013123600Z debug 2018-12-10T21:16:15.006 thread-0 apply_context.cpp:28 print_debug ]
2018-12-10T21:16:15.013195500Z [(message,callme)->message]: CONSOLE OUTPUT BEGIN =====================
2018-12-10T21:16:15.013343400Z receiver : message, code : message_code : message, _self : message, get_code: message, get_self : message
2018-12-10T21:16:15.013416400Z [(message,callme)->message]: CONSOLE OUTPUT END =====================
ポイントは、(hello,hi)->message
の処理の時、_code
がhello
になっているところです。
receiver : message, code : hello_code : hello, _self : message, get_code: hello, get_self : message
まとめ
- 処理の中では、関数が所属しているコントラクト名を使いたい場合は、
_self
を使う - 通知を受け取る時は、
_code
で通知元を判定できる