Solidity

Solidity keccak 行為

  • February 11, 2020

我有一個奇怪的問題。我正在嘗試在 Rust 中 keccak256 打包編碼參數

$$ which should mimic Soldity’s behavior to be checked on chain later $$. 我暫時失敗了。為了解決這個問題,我一直在編寫一個具有以下功能的小型測試合約:

   function doKeccak(bytes memory _data) public pure returns (bytes32) {
       return keccak256(_data);
   }

   function packed(
       address _from,
       address _to,
       uint256 _value,
       bytes memory _data,
       uint256 _nonce,
       uint256 _gasPrice,
       uint256 _gasLimit
   ) public pure returns (bytes memory) {
       return
           abi.encodePacked(
               bytes1(0x19),
               bytes1(0),
               _from,
               _to,
               _value,
               _data,
               _nonce,
               _gasPrice,
               _gasLimit
           );
   }

  function doKeccakPacked(
       address _from,
       address _to,
       uint256 _value,
       bytes memory _data,
       uint256 _nonce,
       uint256 _gasPrice,
       uint256 _gasLimit
   ) public pure returns (bytes32) {
       return
           keccak256(
               abi.encodePacked(
                   bytes1(0x19),
                   bytes1(0),
                   _from,
                   _to,
                   _value,
                   _data,
                   _nonce,
                   _gasPrice,
                   _gasLimit
               )
           );
   }

現在,如果我打電話給 rust 程序

$$ pseudo-code $$ contract.doKeccakPacked(args..)我得到不同的contract.doKeccak(contract.packed(args))結果…… 任何的想法 ?

編輯 例如,這裡是一個原始的 Rust 參數數組,它會導致不同的結果:

[
   Address(
       0xdfa1468d07fc86840a6eb53e0e65cebde81d1af9,
   ),
   Address(
       0x7f114fc87edc5f1311d4e77d1a3018a3dc34f47e,
   ),
   Uint(
       0,
   ),
   Bytes(
       [
           201,
           13,
           180,
           71,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           127,
           17,
           79,
           200,
           126,
           220,
           95,
           19,
           17,
           212,
           231,
           125,
           26,
           48,
           24,
           163,
           220,
           52,
           244,
           126,
       ],
   ),
   Uint(
       94481061581245121,
   ),
   Uint(
       0,
   ),
   Uint(
       250000,
   ),
]

編輯 2

這是生鏽程式碼:

fn hash_sign(
       &self,
       wallet: Address,
       data: ethabi::Bytes,
       nonce: U256,
   ) -> Result<Bytes, String> {
       let options = Options::default();

       // this is the contract whose test functions are above
       let erc_1077_hash_abi = ethabi::Contract::load(constants::abis::ERC1077_HASH).unwrap();
       let erc_1077_hash_address = Address::from_str(&"83649266Ba0a8CAd860403a6532F12c6074BBDAC").unwrap();

       let function = erc_1077_hash_abi.function("doKeccakPacked").unwrap();
       let params: [ethabi::Token; 7] = [
           ethabi::Token::Address(self.address),
           ethabi::Token::Address(wallet),
           ethabi::Token::Uint(self.value()),
           ethabi::Token::Bytes(data.clone()),
           ethabi::Token::Uint(nonce),
           ethabi::Token::Uint(self.gas_price()),
           ethabi::Token::Uint(self.gas_limit()),
       ];

       let encoded = function.encode_input(&params).unwrap();
       let result_1 = self.web3.eth().call(
           CallRequest {
               from: None,
               to: erc_1077_hash_address,
               gas: options.gas,
               gas_price: options.gas_price,
               value: options.value,
               data: Some(Bytes(encoded)),
           },
           None.into(),
       );

       let result_1 = match result_1.wait() {
         Ok(s) => Ok(s),
         Err(_e) => Err(format!("error")),
     };

       let function = erc_1077_hash_abi.function("packed").unwrap();
       let encoded = function.encode_input(&params).unwrap();

       let packed = self.web3.eth().call(
           CallRequest {
               from: None,
               to: erc_1077_hash_address,
               gas: options.gas,
               gas_price: options.gas_price,
               value: options.value,
               data: Some(Bytes(encoded.clone())),
           },
           None.into(),
       );

       let packed = packed.wait().unwrap();
       let packed = packed.0;

       let function = erc_1077_hash_abi.function("doKeccak").unwrap();
       let params: [ethabi::Token; 1] = [
           ethabi::Token::Bytes(packed),
       ];
       let encoded = function.encode_input(&params).unwrap();

       let result_2 = self.web3.eth().call(
           CallRequest {
               from: None,
               to: erc_1077_hash_address,
               gas: options.gas,
               gas_price: options.gas_price,
               value: options.value,
               data: Some(Bytes(encoded)),
           },
           None.into(),
       );

       let result_2 = match result_2.wait() {
         Ok(s) => Ok(s),
         Err(_e) => Err(format!("error")),
     };


       result_1
   }

這裡 result_1 和 result_2 是不同的……

其實我想通了。這不是keccak問題,而是與web3rust crate 解碼從鏈返回的字節數據的方式有關的問題。它強制執行一些奇怪的填充 - 將其轉換為FixedBytes類型 - 從而弄亂整個工作流程。

謝謝大家。

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