Solidity

Solidity 的 keccak256 雜湊與 WEB3 keccak 雜湊不匹配

  • April 22, 2022

TL;DR:我在契約中有一個計算 keccak256 雜湊的方法,我試圖在 Web3 中複製它,但雜湊不匹配。我的問題與此問題中的問題非常相似,但那裡的答案對我沒有幫助。這可能是編碼問題,但我不確定如何解決。


我試圖像這樣散列三個參數:

pragma solidity >=0.7.0 <0.9.0;
contract Test {
   function makeHash(uint intValue, string calldata strValue) public view returns (bytes32) {
       bytes32 myHash = keccak256(abi.encode(intValue, strValue, msg.sender));
       return myHash;
   }
}

呼叫makeHash(1, 'test1')此地址0x5B38Da6a701c568545dCfcB03FcB875f56beddC4返回0x94822408407fb535100a4152f8709ed58507e1b3dfd32798d25051065f680d64

在 Web3 中,我嘗試連接字元串中的值(我現在意識到這是錯誤的,但也不確定如何在 web3 中執行此操作):web3.utils.keccak256("1test10x5B38Da6a701c568545dCfcB03FcB875f56beddC4")返回0xcd347147b43e04263a58ca2b6d0f0aa8a3e0b00bd02c0e9bbee008aad68b1bf0

從這個答案我也嘗試了這種方法:

web3.utils.soliditySha3(
   { type: 'uint', value: 1 },
   { type: 'string', value: 'test1' },
   { type: 'address', value: '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4' }
)

它返回0x0aca86dcfc0a652e35268737960c05e51eb03dbfc4c175fd3ca094a2e99e180c


由於所有方法都返回了不同的雜湊值,我決定測試只對合約和 web3 中的字元串進行雜湊處理,但即便如此,它們也會生成不同的雜湊值。

bytes32 myHash = keccak256(abi.encode(strValue));

使用合約中的 aboce 行,呼叫makeHash('test1')返回0xf5e2ed7011d2249ef10becf6f745e4b900ab43c0dc529b97d308f25bb36416d0

但是在 web3 中,所有這些方法都返回相同的雜湊值:

web3.utils.keccak256("test1")
web3.utils.sha3Raw('test1')
web3.utils.sha3('test1')
web3.utils.soliditySha3('test1')
web3.utils.soliditySha3Raw('test1')
// Tried encoding
web3.utils.sha3('test1', {encoding: 'String'})
web3.utils.sha3('test1', {encoding: 'hex'})
web3.utils.sha3('test1', {encoding: 'string'})
// Tried converting to hex
web3.utils.soliditySha3Raw(web3.utils.asciiToHex('test1'))
web3.utils.keccak256(web3.utils.asciiToHex('test1'))
// Tried from this answer https://ethereum.stackexchange.com/a/74082/68459
web3.utils.soliditySha3({ type: 'string', value: 'test1' })

他們都回來了0x6d255fc3390ee6b41191da315958b7d6a1e5b17904cc7683558f98acc57977b4


此外,決定嘗試abi.encode通過使用在 web3 中進行複制,web3.eth.abi.encodeParameter(String, 'test1')但它總是返回錯誤:

   if (type.match(paramTypeBytesArray) || type.match(paramTypeNumberArray)) {
            ^
Uncaught TypeError: type.match is not a function
   at ABICoder.formatParam (..\truffle\build\webpack:\node_modules\web3-eth-abi\src\index.js:255:1)
   at ..\truffle\build\webpack:\node_modules\web3-eth-abi\src\index.js:117:1
   at Array.map (<anonymous>)
   at ABICoder.encodeParameters (..\truffle\build\webpack:\node_modules\web3-eth-abi\src\index.js:105:1)
   at ABICoder.encodeParameter (..\truffle\build\webpack:\node_modules\web3-eth-abi\src\index.js:88:1)
   at evalmachine.<anonymous>:0:14
   at sigintHandlersWrap (vm.js:274:15)
   at Script.runInContext (vm.js:128:14)
   at runScript (..\truffle\build\webpack:\packages\core\lib\console.js:270:1)
   at Console.interpret (..\truffle\build\webpack:\packages\core\lib\console.js:285:1)
   at bound (domain.js:426:14)
   at REPLServer.runBound [as eval] (domain.js:439:12)
   at REPLServer.onLine (repl.js:760:10)
   at REPLServer.emit (events.js:315:20)
   at REPLServer.EventEmitter.emit (domain.js:482:12)
   at REPLServer.Interface._onLine (readline.js:329:10)
   at REPLServer.Interface._line (readline.js:658:8)
   at REPLServer.Interface._ttyWrite (readline.js:999:14)
   at REPLServer.self._ttyWrite (repl.js:851:9)
   at ReadStream.onkeypress (readline.js:205:10)
   at ReadStream.emit (events.js:315:20)
   at ReadStream.EventEmitter.emit (domain.js:482:12)

abi.encode函式使用 Solidity 的 ABI規範對合約呼叫的參數進行編碼。對於 uintXXX、bool、address 等固定大小的類型,這很簡單,只需將它們填充到 32 個字節即可;對於動態類型,它很複雜。

相當於這個 Solidity 程式碼:

bytes32 myHash = keccak256(abi.encode('test1'));

在 JavaScript 中將是:

const encoded = web3.eth.abi.encodeParameters(['string'],['test1'])
const hash = web3.utils.sha3(encoded, {encoding: 'hex'})
console.log(hash)

如果你好奇,’test1’ ABI 編碼是:

0x
0000000000000000000000000000000000000000000000000000000000000020   // offset
0000000000000000000000000000000000000000000000000000000000000005   // length
7465737431000000000000000000000000000000000000000000000000000000   // data

makeHash在您的情況下, JavaScript 中的等價物是:

const encoded = web3.eth.abi.encodeParameters(['uint256', 'string', 'address'],[1234, 'country roads', 0x44444..])
const hash = web3.utils.sha3(encoded, {encoding: 'hex'})

引用自:https://ethereum.stackexchange.com/questions/96697