2.6 外部合约的内联操作

之前我们向合同中定义的action进行了内联操作。 在本教程,我们将探讨向外部合同发送操作。 由于我们已经学了许多相关的合约创作,我们将尽量让本教程中的合约看起里简单。 我们将编写一份用于统计合约写入次数的合约。 虽然该类合约在实际中并未被广泛使用,但它能说明如何对外部合约进行内联操作调用。

第1步:创建地址簿计数器合约

导航到CONTRACTS_DIR,创建一个名为abcounter的目录并创建abcounter.cpp文件

在喜欢的编辑器中打开abcounter.cpp文件,并将以下代码粘贴到该文件中。 这份合约是非常基本的,并且在很大程度上都是之前讲解到的知识。 未涉及到的内容,下面也对此做了全面的讲解。

上面代码中唯一涉及的新内容是,这个合约将使用require_auth对此合约中的一个调用到地址簿合同的操作进行限制 。

第2步:为“abcounter”合约创建帐户

打开终端并执行以下命令以创建abcounter用户。

第3步:编译和部署

最后,部署abcounter合同。

第4步:修改addressbook合约,将内联action发送到abcounter

立即导航到您的地址簿目录。

在您喜欢的编辑器中打开addressbook.cpp文件。在本系列的最后部分,我们将对自己的合约进行了内联操作。向我们新的合约发送内联ation,并在合约的私有区域中创建另一个名为increment_counter的帮助程序。

现在,将以下调用添加到各自操作范围中的帮助程序。

现在你的addressbook.c ++合约应该是这样的。

第5步:重新编译并部署`addressbook’合约

重新编译addressbook.cpp合约,因为我们的更改都没有影响ABI,我们不需要重新生成ABI。

eosio-cpp -o addressbook.wasm addressbook.cpp

重新部署合约

第6步:测试

我们已经部署了cbcounter并重新部署了addressbook,我们可以开始进行一些测试。

结果

executed transaction: cc46f20da7fc431124e418ecff90aa882d9ca017a703da78477b381a0246eaf7  152 bytes  1493 us
# addressbook <= addressbook::upsert {"user":"alice","first_name":"alice","last_name":"liddell","street":"123 drink me way","city":"wonde...
# addressbook <= addressbook::notify {"user":"alice","msg":"alice successfully modified record in addressbook"}
# alice <= addressbook::notify {"user":"alice","msg":"alice successfully modified record in addressbook"}
# abcounter <= abcounter::count {"user":"alice","type":"modify"}

计数器已成功被调用通知, 我们现在检查表格。

以防万一,我们需测试其他的action,我们知道alice已经存在一行,所以upsert会修改记录。

擦除:

接下来,我们将测试是否可以直接调用abcounter合约中的数据。

检查abcounter中的表格,我们将看到以下内容:

由于我们向N(地址簿)请求_auth,只有地址簿合约才能成功执行此操作,alice对数字修改的调用对表没有影响。

补充

以下的部分能根据修改所做的更改发送自定义收据,如果在修正期间未进行任何更改,则收据将反映此情况。 这段代码虽然有效,但编写效率较低。 你能优化它吗?

Copy

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>

using namespace eosio;

class addressbook : public eosio::contract {

public:
using contract::contract;

addressbook(account_name self): contract(self) {}

[[eosio::action]]
void upsert(account_name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
require_auth( user );
address_index addresses(_self, _self);
auto iterator = addresses.find( user );
if( iterator == addresses.end() )
{
addresses.emplace(user, [&]( auto& row ) {
row.key = user;
row.first_name = first_name;
row.last_name = last_name;
row.street = street;
row.city = city;
row.state = state;
});
send_summary(user, "successfully emplaced record to addressbook");
increment_counter(user, "emplace");
}
else {
std::string changes;
addresses.modify(iterator, user, [&]( auto& row ) {

if(row.first_name != first_name) {
row.first_name = first_name;
changes += "first name ";
}
if(row.last_name != last_name) {
row.last_name = last_name;
changes += "last name ";
}
if(row.street != street){
row.street = street;
changes += "street ";
}
if(row.city != city){
row.city = city;
changes += "city ";
}
if(row.state != state){
row.state = state;
changes += "state ";
}
});
if(changes.length() > 0) {
send_summary(user, "successfully modified record in addressbook. Fields changed: " + changes);
increment_counter(user, "modify");
} else {
send_summary(user, "called upsert, but request resulted in no changes.");
}
}
}

[[eosio::action]]
void erase(account_name user){
require_auth(user);
address_index addresses(_self, _self);
auto iterator = addresses.find( user );
eosio_assert(iterator != addresses.end(), "Record does not exist");
addresses.erase(iterator);
send_summary(user, "successfully erased record from addressbook");
increment_counter(user, "erase");
}

[[eosio::action]]
void notify(account_name user, std::string msg) {
require_auth(get_self());
require_recipient(user);
}

private:
struct [[eosio::table]] person {
account_name key;
std::string first_name;
std::string last_name;
std::string street;
std::string city;
std::string state;
uint64_t primary_key() const { return key; }
};
typedef eosio::multi_index<N(people), person> address_index;

void send_summary(account_name user, std::string message){
action(
permission_level{get_self(),N(active)},
get_self(),
N(notify),
std::make_tuple(user, name{user}.to_string() + " " + message)
).send();
}

void increment_counter(account_name user, std::string type){
action(
permission_level{get_self(),N(active)},
N(abcounter),
N(count),
std::make_tuple(user, type)
).send();
}

};

EOSIO_ABI( addressbook, (upsert)(notify)(erase) )

原文链接:https://developers.eos.io/eosio-home/docs/sending-an-inline-transaction-to-external-contract