Python

在 pytest 上使用 populus 時,我如何將字節數組作為智能合約的輸入傳輸到 Solidity 瀏覽器中?

  • April 9, 2019

我有以下契約;我可以set()在solidity瀏覽器上使用以下字節數組呼叫。智能合約接受輸入為bytes32。我假設如果看到一個以 開頭的字元串geth,它會將其轉換為格式。solidity browser``0x``byte

以下事務呼叫工作沒有任何問題。

myContract.set("0x15CEF23823A9410D60CB6E6CC56046EC6035A9353100476EA28C94752AF104CD")

myContract.get() 回報:"0x15CEF23823A9410D60CB6E6CC56046EC6035A9353100476EA28C94752AF104CD

我的契約:

contract Contract {
 bytes32 public hash;
 function set(bytes32 hash_) returns (bool success)
 {
       hash = hash_;
 }
 function get() constant returns bytes32 {
    return hash;
  }
}

我想對 Populus 做同樣的操作。當我嘗試將其稱為 on 時test_greeter.py

def test_greeter(web3, accounts, chain):
   myContract, _ = chain.provider.get_or_deploy_contract('Lottery')
   set_txn_hash = myContract.transact().set("0x15CEF23823A9410D60CB6E6CC56046EC6035A9353100476EA28C94752AF104CD")

它給出了以下錯誤,我假設 python 將輸入set()視為字元串而不是字節。並且輸入的字元串版本超過了byte32.

  @classmethod
   def _encode_abi(cls, abi, arguments, data=None):
       argument_types = get_abi_input_types(abi)

       if not check_if_arguments_can_be_encoded(abi, arguments, {}):
           raise TypeError(
               "One or more arguments could not be encoded to the necessary "
               "ABI type.  Expected types are: {0}".format(
>                   ', '.join(argument_types),
               )
           )
E           TypeError: One or more arguments could not be encoded to the necessary ABI type.  Expected types are: bytes32

**$$ Q $$**在 pytest 上使用 Populus 時,如何像在solidity 瀏覽器中一樣將字節數組作為契約的輸入傳輸?

感謝您寶貴的時間和幫助。

哪裡有問題?

在更廣泛的堆棧跟踪中,您會看到它_encode_abi實際上是 in web3.py,因此它更多的是 web3 問題而不是 populus 問題。

這在 web3.py v3 中是一個長期存在的問題,並且 v4-beta 可以按預期工作;您可以將十六進製字元串傳遞給 ABIbytes*參數。請參閱討論此問題的https://github.com/ethereum/web3.py/issues/329 。不幸的是,我認為目前還沒有與 v4 兼容的 populus 版本。

什麼是最好的解決方案?

阿爾珀的回答是有效的。在 web3 v3 中,參數必須作為 pythonbytes類型傳入。

轉換為字節的“Web3 方式”將使用Web3.toBytes(),例如:

def test_greeter(web3, accounts, chain):

  hex_str = "0xadc4f61a8a9995668f01ef1e2a0977be34c1d74d925a9a33d7f0b8fb4972a1ce";
  data    = web3.toBytes(hexstr= hex_str);

  set_txn_hash = myContract.transact().set(data);

  ret = myContract.call().get()
  ret = web3.toHex(ret.encode('latin-1'))[2:]    

為什麼必須將參數作為 傳遞bytes

這種行為部分是需要支持 python 2 的副作用,它無法區分 和 之間的bytes區別str。所以 web3 必須選擇是支持原生 pythonbytes類型,還是支持十六進制編碼的字元串。它無法可靠地檢測到差異。由於 web3 v4 需要 python3,它可以區分,並接受ABI類型的bytes或十六進制參數。str``bytes*

如何驗證這是行為?

不幸的是,關於這種行為的文件並不多,所以我們必須查看原始碼。決定參數是否映射到 ABI 類型的程式碼位於web3.utils.abi.is_encodable()

def is_encodable(_type, value):
   ...
   elif base == 'bytes':
       if not is_string(value):
           return False

       if not sub:
           return True

       max_length = int(sub)
       return len(value) <= max_length

因為十六進制編碼的字元串長度為 64 或 66 個字元,並且bytes32參數的長度為 32,所以此is_encodable()測試將返回False. 由於此函式返回False,web3 將拒絕呼叫,說參數無法編碼為 bytes32。

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