eosio.system智能合约介绍(四)合约部署介绍

01

目的

本文档结合系统合约,介绍了合约部署的核心概念和步骤,包括合约部署过程以及setcode和setabi方法,帮助初学者和开发者快速了解和掌握EOS系统合约部署的相关知识。

02

概述

“eosio.system”智能合约是eos的系统命令合约。这个合约几乎实现了eos全部的系统命令,包括创建账户、资源质押、超级节点投票、域名竞拍等功能,它定义了区块链核心功能所需的结构和操作。

下文将介绍合约部署的相关知识。

03

环境准备

(一)一条正在运行且可访问的区块链

中移链(基于EOS)测试环境搭建

(二)确保本地钱包已打开并解锁

如何创建钱包:

https://developers.eos.io/manuals/eos/latest/cleos/how-to-gui...

04

合约部署介绍

(一)合约部署过程

假设您要将合约部署到的帐户名称是addressbook,请执行以下命令:

cleos set contract addressbook you_local_path_to/addressbook/ -p addressbook@active

命令详解:

set contract:cleos 工具的子命令,用于部署合约

addressbook:要部署合约的账户名称,即目标账户。请将 addressbook 替换为您自己的账户名称

you_local_path_to/addressbook/:合约的本地路径,指定了合约的位置。请将 /your_local_path_to/替换为您本地的实际路径,最好是绝对路径

-p addressbook@active:指定操作的权限。在这种情况下,-p参数后面的addressbook表示使用 addressbook 账户的active权限进行操作。请确保addressbook账户具有足够的权限来部署合约

通过运行这个命令,合约将被部署到addressbook账户。

得到如下结果:

Reading WASM from /home/xxx/biosboot/genesis/test/addressbook/addressbook.wasm...
Publishing contract...
executed transaction: ea09081dc5e42bd1f2b5abe619a7388e1e52ec16a91adb221f3ecb11fa566dde  17840 bytes  16689 us
#         eosio <= eosio::setcode               {"account":"addressbook","vmtype":0,"vmversion":0,"code":"0061736d01000000019a022a60000060037f7f7f01...
#         eosio <= eosio::setabi                {"account":"addressbook","abi":"0e656f73696f3a3a6162692f312e32000305657261736500010475736572046e616d...

部署EOSIO合约时,需经历以下步骤:

读取WAST/WASM文件:读取存放在build目录下的WAST/WASM文件,这些文件是要部署的合约的编译结果;

装配WASM:对于读取的WAST/WASM文件,进行装配,将合约的二进制代码准备好供后续操作使用。

将合约发布到区块链上

执行交易(合约也是一个交易),需要执行两个关键动作:

setcode:该动作用于在区块链上部署或更新账户的合约代码。

setabi:该动作用于为通过account名称标识的合约设置ABI(ApplicationBinaryInterface)。尽管在技术上ABI是可选的,但所有EOSIO工具都依赖于它以提供更便捷的合约交互体验。

执行完以上操作后,合约已成功部署到EOS区块链中的addressbook账户上。

从结果可以看出,调用

cleossetcontractaddressbookyou_local_path_to/addressbook/-paddressbook

等价于调用:

cleos push action addressbook setcode '[addressbook.wasm]' -p addressbook
cleos push action addressbook setabi '[addressbook.abi]' -p addressbook

(二)setcode方法介绍

setcode操作是EOSIO中的一种操作,用于在区块链上部署或更新账户的合约代码。它用于部署或更新与账户关联的智能合约。在使用setcode操作部署或更新合约时,会检查合约是否已经在运行代码。

具体而言,当执行setcode操作时,EOSIO会获取合约的wasm文件,并对其进行处理。在处理过程中,会计算wasm文件的哈希值,以表示该合约的唯一标识。这个哈希值可以用于比对合约的版本和完整性,以确保在部署或更新合约时没有出现错误或篡改。

1、setcode源码介绍

/**
* Set code action sets the contract code for an account.
*
* @param account - the account for which to set the contract code.
* @param vmtype - reserved, set it to zero.
* @param vmversion - reserved, set it to zero.
* @param code - the code content to be set, in the form of a blob binary..
*/
[[eosio::action]]
void setcode( name account, uint8_t vmtype, uint8_t vmversion, const std::vector& code ) {}

参数详解:

account:要部署或更新代码的账户名称

vmtype:此参数保留,应设置为零

vmversion:此参数保留,应设置为零

code:合约代码的二进制表示

2、setcode操作的实现

读取合约的WAST或WASM文件:

合约的开发人员提供合约代码的文件,这可以是WAST(WebAssemblyText)或WASM(WebAssemblyBinary)格式。

装配合约代码:

读取的合约文件需要进行装配,即将其转换为内部可执行的格式,以便区块链节点能够理解和执行。

存储合约代码:

装配后的合约代码将被存储在区块链上,并与指定的账号关联起来。这样,当其他用户或合约需要调用该合约时,可以通过发送交易指向该账号,并执行相应的合约操作。

通过setcode操作,合约的代码被安全地存储在区块链上,并与账号关联。这样,所有参与者都可以通过调用合约的操作来执行合约的功能,而节点可以验证合约的代码哈希值,确保合约的代码没有被篡改,从而保障合约在执行过程中的安全性和可靠性。

(三)setabi方法介绍

setabi操作用于为通过account名称标识的合约设置ABI(ApplicationBinaryInterface)。它在abi_hash_table索引中创建一个条目,使用account名称作为键,如果尚不存在,并将其值设置为ABI的哈希值。如果已存在,则更新现有account键的当前ABI哈希值。

1、setabi源码介绍

源码:

  /**
          * Set abi action sets the abi for contract identified by `account` name. Creates an entry in the abi_hash_table
          * index, with `account` name as key, if it is not already present and sets its value with the abi hash.
          * Otherwise it is updating the current abi hash value for the existing `account` key.
          *
          * @param account - the name of the account to set the abi for
          * @param abi     - the abi hash represented as a vector of characters
          */
         [[eosio::action]]
         void setabi( name account, const std::vector& abi )
{
           abi_hash_table table(get_self(), get_self().value);
           auto itr = table.find( account.value );
           if( itr == table.end() ) {
              table.emplace( account, [&]( auto& row ) {
                 row.owner = account;
                 row.hash  = eosio::sha256(const_cast(abi.data()), abi.size());
              });
           } else {
              table.modify( itr, eosio::same_payer, [&]( auto& row ) {
                 row.hash = eosio::sha256(const_cast(abi.data()), abi.size());
              });
           }
        }

参数详解:

account:要部署ABI的目标账户的名称。它是一个name类型的参数,表示EOSIO中的账户名

abi:要设置的合约的ABI数据,以std::vector类型的参数传入

源码详解:

通过abi_hash_table类创建一个名为table的表对象。该表用于存储账户的abi哈希值。

使用table.find()函数查找表中是否已经存在与目标账户相关的记录。

如果在表中没有找到与目标账户相关的记录(即itr==table.end()),则执行table.emplace()操作。

在table.emplace()中,通过lambda表达式将新的记录插入到表中。lambda表达式接收一个row参数,用于访问新插入的记录。在lambda表达式中,将row.owner设置为目标账户的名称,将row.hash设置为传入的ABI数据的SHA256哈希值。

如果在表中找到了与目标账户相关的记录(即itr!=table.end()),则执行table.modify()操作。

在table.modify()中,通过lambda表达式修改找到的记录。这里使用eosio::same_payer权限,确保修改操作的付款账户与原始记录的付款账户相同。在lambda表达式中,将row.hash更新为传入的ABI数据的SHA256哈希值。

ABI的实际存储方式在EOSIO中与常见的JSON文件存储方式存在较大的差异。相反,ABI被以一种被称为"原始ABI"的打包方式进行存储。

传统的开发环境中通常将ABI表示为JSON格式的文件,其中包含了合约的接口和数据结构定义。然而,在EOSIO中为了减少存储空间和提高效率,ABI被以一种更紧凑的格式进行存储。

“原始ABI”是指将ABI数据按照一定的规则进行打包和编码,以减少其存储空间。这种打包方式不同于常见的JSON文件格式,它更加紧凑,节省了存储空间,并提高了读取和解析的效率。原始ABI存储方式在EOSIO中被使用,以满足区块链中存储资源的限制和性能需求。

每个ABI都需要包含一组特定的字段,这些字段用于描述合约的不同方面,如版本信息、类型定义、结构定义、操作定义、表格定义等。这些字段的内容将被序列化为一种更节省空间的表示形式。

在EOSIO中,ABI用于定义合约的接口和数据结构。为了方便存储和传输,ABI需要被序列化为一种紧凑的二进制格式,以节省存储空间和网络带宽。

具体而言,一个典型的ABI包含以下字段:

version:ABI的版本信息,用于标识ABI的兼容性和支持的特性

types:类型定义,用于描述合约中使用的自定义类型,如结构体、枚举等

structs:结构定义,描述合约中的数据结构,包括结构体的名称、字段和类型等

actions:操作定义,描述合约中可执行的操作,包括操作的名称、参数和返回类型等

tables:表格定义,描述合约中的数据表格,包括表格的名称、字段和索引等

当执行setabi操作时,合约的ABI数据可以以两种形式之一进行提供:二进制文件或JSON文件。二进制文件是指以二进制格式存储的ABI数据文件,而JSON文件则是指以JSON格式存储的文本文件。

setabi操作需要能够处理这两种形式的ABI数据,并进行相应的转换。具体而言,它可以将二进制文件转换为JSON格式的ABI数据,或将JSON格式的ABI数据转换为二进制格式,即序列化和反序列化的过程。这样,合约开发人员可以选择以更适合他们的方式提供ABI数据,并将其转换为适合在区块链上存储和使用的形式。

END

你可能感兴趣的:(区块链)