_code と _self の違い

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
```c++
#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

```c++
#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))
```

### 実験
上記２つコントラクトをコンパイルしてデプロイしておいてから、実行してみると

```shell
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` 側のログで確認すると、

```shell
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` アカウントに通知する

```c++
#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` メソッドも定義して、プリントアウトしています。

```c++
#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))
```

実行すると、

```shell
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`側のログは、下記のようになっています

```shell
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` で通知元を判定できる