Solidity

無法使用 Web3 在 Solidity 智能合約中正確儲存字元串

  • May 24, 2017

我正在處理一個非常簡單的智能合約:

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

然後我使用 web3getData()生成事務有效負載:

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方法,使用相同的值,它顯然有效!

我發現了問題。

這個錯誤確實是我所懷疑的:有效載荷沒有正確序列化,因此智能合約介面無法將正確數量的字節放入正確的“插槽”中。

原因?我的錯…

hashrecord方法的第一個參數。此外,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前綴,所以將它們辨識為普通字元串,因此會自動將它們轉換為十六進制。

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