如果你想知道在EOS上部署了什么版本的智能合約合是,你需要查看代碼哈希同辣。我們將看到如何計(jì)算代碼和ABI哈希冻记,并編寫一個(gè)函數(shù)晦毙,通過比較它們的哈希來查看本地WASM文件是否與正在運(yùn)行的協(xié)議相匹配。
EOS代碼的哈希
當(dāng)通過eosio
setcode
操作設(shè)置或更新合約時(shí)洽蛀,檢查合約代碼是否已經(jīng)在運(yùn)行摹迷。因此,通過查看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è)簡單的WASM字節(jié)表示的sha256哈希值。(第二個(gè)參數(shù)只是字節(jié)數(shù)組的長度驮审,哈希函數(shù)需要它來知道要對多少字節(jié)進(jìn)行哈希處理鲫寄。)
在node.js中,我們可以通過哈希一個(gè)WASM文件并將其與區(qū)塊鏈上代碼的哈希值進(jìn)行比較來輕松實(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)地来,可以通過一個(gè)查詢同時(shí)獲取帳戶的代碼和abi哈希。
注意熙掺,WASM文件和代碼哈希依賴于編譯期間使用的eosio cpp
版本和-o
優(yōu)化參數(shù)未斑。來自同一個(gè)C++代碼,代碼哈媳壹ǎ可能是不同的蜡秽。
EOS ABI 的哈希
我們可以嘗試同樣的方法來計(jì)算ABI哈希,但是缆镣,由于某種原因芽突,eosio setabi
操作不檢查ABI哈希,因此允許使用相同的哈希進(jìn)行更新董瞻。
但是get-raw-abi-api
端點(diǎn)返回一個(gè)abi哈希寞蚌,因此必須從某個(gè)地方獲取它。通過檢查nodeos-chain
插件,我們可以看到它是為每個(gè)請求動(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í)際存儲ABI的方式有一個(gè)很大的區(qū)別。它不是作為熟悉的JSON文件存儲的煞聪,而是作為EOS稱之為原始ABI的打包方式存儲的斗躏。
從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
啄糙、types
、structs
云稚、actions
隧饼、tables
,即版本静陈、類型燕雁、結(jié)構(gòu)、操作鲸拥、表等拐格,然后將這些字段序列化為更大的有效表示形式。
計(jì)算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等區(qū)塊鏈相關(guān)的交互式在線編程實(shí)戰(zhàn)教程:
- EOS入門教程,本課程幫助你快速入門EOS區(qū)塊鏈去中心化應(yīng)用的開發(fā)撞叨,內(nèi)容涵蓋EOS工具鏈金踪、賬戶與錢包、發(fā)行代幣牵敷、智能合約開發(fā)與部署胡岔、使用代碼與智能合約交互等核心知識點(diǎn),最后綜合運(yùn)用各知識點(diǎn)完成一個(gè)便簽DApp的開發(fā)劣领。
- 深入淺出玩轉(zhuǎn)EOS錢包開發(fā)姐军,本課程以手機(jī)EOS錢包的完整開發(fā)過程為主線铁材,深入學(xué)習(xí)EOS區(qū)塊鏈應(yīng)用開發(fā)尖淘,課程內(nèi)容即涵蓋賬戶、計(jì)算資源著觉、智能合約村生、動(dòng)作與交易等EOS區(qū)塊鏈的核心概念,同時(shí)也講解如何使用eosjs和eosjs-ecc開發(fā)包訪問EOS區(qū)塊鏈饼丘,以及如何在React前端應(yīng)用中集成對EOS區(qū)塊鏈的支持趁桃。課程內(nèi)容深入淺出,非常適合前端工程師深入學(xué)習(xí)EOS區(qū)塊鏈應(yīng)用開發(fā)。
- java比特幣開發(fā)教程卫病,本課程面向初學(xué)者油啤,內(nèi)容即涵蓋比特幣的核心概念,例如區(qū)塊鏈存儲蟀苛、去中心化共識機(jī)制益咬、密鑰與腳本、交易與UTXO等帜平,同時(shí)也詳細(xì)講解如何在Java代碼中集成比特幣支持功能幽告,例如創(chuàng)建地址、管理錢包裆甩、構(gòu)造裸交易等冗锁,是Java工程師不可多得的比特幣開發(fā)學(xué)習(xí)課程。
- php比特幣開發(fā)教程嗤栓,本課程面向初學(xué)者冻河,內(nèi)容即涵蓋比特幣的核心概念,例如區(qū)塊鏈存儲茉帅、去中心化共識機(jī)制芋绸、密鑰與腳本、交易與UTXO等担敌,同時(shí)也詳細(xì)講解如何在Php代碼中集成比特幣支持功能摔敛,例如創(chuàng)建地址、管理錢包全封、構(gòu)造裸交易等马昙,是Php工程師不可多得的比特幣開發(fā)學(xué)習(xí)課程。
- c#比特幣開發(fā)教程刹悴,本課程面向初學(xué)者行楞,內(nèi)容即涵蓋比特幣的核心概念,例如區(qū)塊鏈存儲土匀、去中心化共識機(jī)制子房、密鑰與腳本、交易與UTXO等就轧,同時(shí)也詳細(xì)講解如何在C#代碼中集成比特幣支持功能证杭,例如創(chuàng)建地址、管理錢包妒御、構(gòu)造裸交易等解愤,是C#工程師不可多得的比特幣開發(fā)學(xué)習(xí)課程。
- java以太坊開發(fā)教程乎莉,主要是針對java和android程序員進(jìn)行區(qū)塊鏈以太坊開發(fā)的web3j詳解送讲。
- python以太坊奸笤,主要是針對python工程師使用web3.py進(jìn)行區(qū)塊鏈以太坊開發(fā)的詳解。
- php以太坊哼鬓,主要是介紹使用php進(jìn)行智能合約開發(fā)交互监右,進(jìn)行賬號創(chuàng)建、交易异希、轉(zhuǎn)賬秸侣、代幣開發(fā)以及過濾器和交易等內(nèi)容。
- 以太坊入門教程宠互,主要介紹智能合約與dapp應(yīng)用開發(fā)味榛,適合入門。
- 以太坊開發(fā)進(jìn)階教程予跌,主要是介紹使用node.js搏色、mongodb、區(qū)塊鏈券册、ipfs實(shí)現(xiàn)去中心化電商DApp實(shí)戰(zhàn)频轿,適合進(jìn)階。
- ERC721以太坊通證實(shí)戰(zhàn)烁焙,課程以一個(gè)數(shù)字藝術(shù)品創(chuàng)作與分享DApp的實(shí)戰(zhàn)開發(fā)為主線航邢,深入講解以太坊非同質(zhì)化通證的概念、標(biāo)準(zhǔn)與開發(fā)方案骄蝇。內(nèi)容包含ERC-721標(biāo)準(zhǔn)的自主實(shí)現(xiàn)膳殷,講解OpenZeppelin合約代碼庫二次開發(fā),實(shí)戰(zhàn)項(xiàng)目采用Truffle九火,IPFS赚窃,實(shí)現(xiàn)了通證以及去中心化的通證交易所。
- C#以太坊岔激,主要講解如何使用C#開發(fā)基于.Net的以太坊應(yīng)用勒极,包括賬戶管理、狀態(tài)與交易虑鼎、智能合約開發(fā)與交互辱匿、過濾器和交易等。
- Hyperledger Fabric 區(qū)塊鏈開發(fā)詳解炫彩,本課程面向初學(xué)者匾七,內(nèi)容即包含Hyperledger Fabric的身份證書與MSP服務(wù)、權(quán)限策略媒楼、通道配置與啟動(dòng)乐尊、鏈碼通信接口等核心概念戚丸,也包含F(xiàn)abric網(wǎng)絡(luò)設(shè)計(jì)划址、nodejs鏈碼與應(yīng)用開發(fā)的操作實(shí)踐扔嵌,是Nodejs工程師學(xué)習(xí)Fabric區(qū)塊鏈開發(fā)的最佳選擇。
- Hyperledger Fabric java 區(qū)塊鏈開發(fā)詳解夺颤,課程面向初學(xué)者痢缎,內(nèi)容即包含Hyperledger Fabric的身份證書與MSP服務(wù)、權(quán)限策略世澜、頻道配置與啟動(dòng)独旷、鏈碼通信接口等核心概念,也包含F(xiàn)abric網(wǎng)絡(luò)設(shè)計(jì)寥裂、java鏈碼與應(yīng)用開發(fā)的操作實(shí)踐嵌洼,是java工程師學(xué)習(xí)Fabric區(qū)塊鏈開發(fā)的最佳選擇。
- tendermint區(qū)塊鏈開發(fā)詳解封恰,本課程適合希望使用tendermint進(jìn)行區(qū)塊鏈開發(fā)的工程師麻养,課程內(nèi)容即包括tendermint應(yīng)用開發(fā)模型中的核心概念,例如ABCI接口诺舔、默克爾樹鳖昌、多版本狀態(tài)庫等,也包括代幣發(fā)行等豐富的實(shí)操代碼低飒,是go語言工程師快速入門區(qū)塊鏈開發(fā)的最佳選擇许昨。
匯智網(wǎng)原創(chuàng)翻譯,轉(zhuǎn)載請標(biāo)明出處褥赊。這里是如何計(jì)算EOS代碼和ABI的哈希