Solidity
無法使用 Web3 在 Solidity 智能合約中正確儲存字元串
我正在處理一個非常簡單的智能合約:
contract MyRegistry { struct MyEvent { string code; // service code, e.g. 1001/FOO/BAR string desc; // long string uint count; bool recorded; } event Record(bytes32 hash, string desc, uint count); function record(bytes32 hash, string code, string desc, uint count) external { if (registry[hash].recorded) throw; registry[hash] = MyEvent(code, desc, count, true); } mapping (bytes32 => MyEvent) public registry; }
然後我使用 web3
getData()
生成事務有效負載:var EthTX = require('ethereumjs-tx') [...] var calldata = Registry.record.getData(hash, code, desc, count) [...] var transaction = new EthTX({ to: registry_address, gasLimit: 500000, gasPrice: +web3.toWei(10, 'gwei'), nonce: myNonce, data: calldata, })
交易順利,但是,
registry
通過 Remix 查詢,我看到:code: "" desc: "" count: 27 recorded: true
字元串沒有被記錄!
我也嘗試過
getData
以這種方式使用:getData(hash, Web3.fromAscii(code), Web3.fromAscii(desc), count)
並以另一種方式:
getData(hash, Web3.toHex(code), Web3.toHex(desc), count)
但結果更糟:
code: "" desc: "<long hex string containing both code and desc strings>" count: 27 recorded: true
我無法理解發生了什麼。就像 web3 無法正確序列化有效負載,因此,智能合約介面無法將正確數量的字節放入正確的“插槽”中。
任何的想法?
PS如果我從 Remix 呼叫該
record
方法,使用相同的值,它顯然有效!
我發現了問題。
這個錯誤確實是我所懷疑的:有效載荷沒有正確序列化,因此智能合約介面無法將正確數量的字節放入正確的“插槽”中。
原因?我的錯…
hash
是record
方法的第一個參數。此外,hash
變數是 keccak256 JS 庫的結果,十六進制編碼。好吧,getData()
以這種方式使用:contract.record.getData(hash, code, desc, count)
是完全錯誤的。
hash
已經是十六進制編碼,但沒有0x
前綴。因此getData()
將其辨識為普通字元串,並將其再次轉換為另一個十六進製字元串。那是什麼意思?這意味著新轉換的十六進製字元串不再適合bytes32
.**解決方案:**添加
0x
前綴以hash
表明getData()
它已經是一個十六進製字元串(即保持不變):contract.record.getData(`0x${hash}`, code, desc, count)
此外,絕對不需要使用
.fromAscii()
其他兩個字元串,getData()
因為它們沒有0x
前綴,所以將它們辨識為普通字元串,因此會自動將它們轉換為十六進制。