如何计算EOS代码和ABI的哈希,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
如果你想知道在EOS上部署了什么版本的智能合约,你需要查看代码哈希。我们将看到如何计算代码和ABI哈希,并编写一个函数,通过比较它们的哈希来查看本地WASM文件是否与正在运行的协议相匹配。
EOS代码的哈希
当通过eosio
setcode
操作设置或更新合约时,检查合约代码是否已经在运行。因此,通过查看setcode
实现,我们可以从WASM文件看到如何计算哈希值。
void apply_eosio_setcode(apply_context& context) { // some setup code fc::sha256 code_id; /// default ID == 0 if( act.code.size() > 0 ) { code_id = fc::sha256::hash( act.code.data(), (uint32_t)act.code.size() ); wasm_interface::validate(context.control, act.code); } const auto& account = db.get<account_object,by_name>(act.account); int64_t code_size = (int64_t)act.code.size(); int64_t old_size = (int64_t)account.code.size() * config::setcode_ram_bytes_multiplier; int64_t new_size = code_size * config::setcode_ram_bytes_multiplier; EOS_ASSERT( account.code_version != code_id, set_exact_code, "contract is already running this version of code" ); // ... }
这只是一个简单的WASM字节表示的sha256哈希值。(第二个参数只是字节数组的长度,哈希函数需要它来知道要对多少字节进行哈希处理。)
在node.js中,我们可以通过哈希一个WASM文件并将其与区块链上代码的哈希值进行比较来轻松实现这一点。
const fs = require(`fs`) const crypto = require(`crypto`) const loadFileContents = file => { if (!fs.existsSync(file)) { throw new Error(`Code file "${file}" does not exist.`) } // no encoding => read as Buffer return fs.readFileSync(file) } const createHash = contents => { const hash = crypto.createHash(`sha256`) hash.update(contents) const digest = hash.digest(`hex`) return digest } // fetch code contract from blockchain const { code_hash: onChainCodeHash, abi_hash } = await api.rpc.fetch(`/v1/chain/get_raw_abi`, { account_name: `hello`, }) const contents = loadFileContents(`contracts/hello.wasm`) const codeHash = createHash(contents) if (codeHash === onChainCodeHash) { console.log(`Code is up-to-date.`) }
get-raw-abi
函数是一个很好的API端点,可以通过一个查询同时获取帐户的代码和abi哈希。
注意,WASM文件和代码哈希依赖于编译期间使用的eosio cpp
版本和-o
优化参数。来自同一个C++代码,代码哈希可能是不同的。
EOS ABI 的哈希
我们可以尝试同样的方法来计算ABI哈希,但是,由于某种原因,eosio setabi
操作不检查ABI哈希,因此允许使用相同的哈希进行更新。
但是get-raw-abi-api
端点返回一个abi哈希,因此必须从某个地方获取它。通过检查nodeos-chain
插件,我们可以看到它是为每个请求动态计算的:
read_only::get_raw_abi_results read_only::get_raw_abi( const get_raw_abi_params& params )const { get_raw_abi_results result; result.account_name = params.account_name; const auto& d = db.db(); const auto& accnt = d.get<account_object,by_name>(params.account_name); result.abi_hash = fc::sha256::hash( accnt.abi.data(), accnt.abi.size() ); result.code_hash = accnt.code_version; if( !params.abi_hash || *params.abi_hash != result.abi_hash ) result.abi = blob{{accnt.abi.begin(), accnt.abi.end()}}; return result; }
计算结果与ABI字节表示的代码哈希 – SHA256 完全相同。然而,实际存储ABI的方式有一个很大的区别。它不是作为熟悉的JSON文件存储的,而是作为EOS称之为原始ABI的打包方式存储的。
从raw abi转换为json很容易使用eosjs
,但是从json转换为raw abi需要一些nb的操作:
const {Serialize, Api} = require(`eosjs`) const {TextEncoder, TextDecoder} = require(`util`) // node only; native TextEncoder/Decoder const jsonToRawAbi = json => { const tmpApi = new Api({ textDecoder: new TextDecoder(), textEncoder: new TextEncoder(), }) const buffer = new Serialize.SerialBuffer({ textEncoder: tmpApi.textEncoder, textDecoder: tmpApi.textDecoder, }) const abiDefinition = tmpApi.abiTypes.get(`abi_def`) // need to make sure abi has every field in abiDefinition.fields // otherwise serialize throws const jsonExtended = abiDefinition.fields.reduce( (acc, {name: fieldName}) => Object.assign(acc, {[fieldName]: acc[fieldName] || []}), json, ) abiDefinition.serialize(buffer, jsonExtended) if (!Serialize.supportedAbiVersion(buffer.getString())) { throw new Error(`Unsupported abi version`) } buffer.restartRead() // convert to node buffer return Buffer.from(buffer.asUint8Array()) }
每个ABI必须包含一组特定的字段,如version
、types
、structs
、actions
、tables
,即版本、类型、结构、操作、表等,然后将这些字段序列化为更大的有效表示形式。
计算ABI哈希并用链上的值检查它是很简单的:
const contents = loadFileContents(`contracts/hello.abi`) const abi = JSON.parse(contents.toString(`utf8`)) const serializedAbi = jsonToRawAbi(abi) const abiHash = createHash(serializedAbi) // fetch abi hash from blockchain const { code_hash, abi_hash: onChainAbiHash } = await api.rpc.fetch(`/v1/chain/get_raw_abi`, { account_name: `hello`, }) if (abiHash === onChainAbiHash) { console.log(`ABI is up-to-date.`) return null }
关于如何计算EOS代码和ABI的哈希问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。
原创文章,作者:254126420,如若转载,请注明出处:https://blog.ytso.com/230658.html