如何計(jì)算EOS代碼和ABI的哈希

如何計(jì)算EOS代碼和ABI的哈希,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到芝罘網(wǎng)站設(shè)計(jì)與芝罘網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、空間域名、虛擬主機(jī)、企業(yè)郵箱。業(yè)務(wù)覆蓋芝罘地區(qū)。

如果你想知道在EOS上部署了什么版本的智能合約,你需要查看代碼哈希。我們將看到如何計(jì)算代碼和ABI哈希,并編寫(xiě)一個(gè)函數(shù),通過(guò)比較它們的哈希來(lái)查看本地WASM文件是否與正在運(yùn)行的協(xié)議相匹配。

EOS代碼的哈希

當(dāng)通過(guò)eosio setcode操作設(shè)置或更新合約時(shí),檢查合約代碼是否已經(jīng)在運(yùn)行。因此,通過(guò)查看setcode實(shí)現(xiàn),我們可以從WASM文件看到如何計(jì)算哈希值。

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" );

   // ...
}

這只是一個(gè)簡(jiǎn)單的WASM字節(jié)表示的sha256哈希值。(第二個(gè)參數(shù)只是字節(jié)數(shù)組的長(zhǎng)度,哈希函數(shù)需要它來(lái)知道要對(duì)多少字節(jié)進(jìn)行哈希處理。)

在node.js中,我們可以通過(guò)哈希一個(gè)WASM文件并將其與區(qū)塊鏈上代碼的哈希值進(jìn)行比較來(lái)輕松實(shí)現(xiàn)這一點(diǎn)。

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函數(shù)是一個(gè)很好的API端點(diǎn),可以通過(guò)一個(gè)查詢(xún)同時(shí)獲取帳戶(hù)的代碼和abi哈希。

注意,WASM文件和代碼哈希依賴(lài)于編譯期間使用的eosio cpp版本和-o優(yōu)化參數(shù)。來(lái)自同一個(gè)C++代碼,代碼哈希可能是不同的。

EOS ABI 的哈希

我們可以嘗試同樣的方法來(lái)計(jì)算ABI哈希,但是,由于某種原因,eosio setabi操作不檢查ABI哈希,因此允許使用相同的哈希進(jìn)行更新。

但是get-raw-abi-api端點(diǎn)返回一個(gè)abi哈希,因此必須從某個(gè)地方獲取它。通過(guò)檢查nodeos-chain插件,我們可以看到它是為每個(gè)請(qǐng)求動(dòng)態(tài)計(jì)算的:

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;
}

計(jì)算結(jié)果與ABI字節(jié)表示的代碼哈希 - SHA256 完全相同。然而,實(shí)際存儲(chǔ)ABI的方式有一個(gè)很大的區(qū)別。它不是作為熟悉的JSON文件存儲(chǔ)的,而是作為EOS稱(chēng)之為原始ABI的打包方式存儲(chǔ)的。

從raw abi轉(zhuǎn)換為json很容易使用eosjs,但是從json轉(zhuǎn)換為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())
}

每個(gè)ABI必須包含一組特定的字段,如version、typesstructs、actionstables,即版本、類(lèi)型、結(jié)構(gòu)、操作、表等,然后將這些字段序列化為更大的有效表示形式。

計(jì)算ABI哈希并用鏈上的值檢查它是很簡(jiǎn)單的:

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
}

關(guān)于如何計(jì)算EOS代碼和ABI的哈希問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

當(dāng)前標(biāo)題:如何計(jì)算EOS代碼和ABI的哈希
標(biāo)題路徑:http://muchs.cn/article26/pppsjg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、域名注冊(cè)、關(guān)鍵詞優(yōu)化、手機(jī)網(wǎng)站建設(shè)、定制開(kāi)發(fā)、用戶(hù)體驗(yàn)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)