我在Solidity中:
struct MyStruct {
string data;
address issuer;
}
function getHash(MyStruct calldata myStruct) public pure returns (bytes32) {
return keccak256(abi.encode(myStruct));
}
在Python中:
from eth_utils import keccak
from eth_abi import encode
myStruct = {
'data': 'Hello',
'issuer': '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4' # Example address
}
def getHash(struct):
return keccak(encode(<NO MATTER WHAT I PUT HERE I CANT GET WHAT I WANT>))
**CONTEXT:**我需要在solidity
中有一些数据和地址。该数据的发送者之前必须发送所述数据的keccak(以某种方式嵌入地址),他必须之前在python中计算哈希。当他稍后发送完整的数据时,我需要合约对该数据进行散列,并将其与用户首先发送的散列进行比较。然后,我需要将地址(在本例中为issuer字段)替换为类似address(0x0)
或address(this)
的内容(这意味着无论交易发送方如何都是常数),最后存储“未签名”哈希。这就是为什么我不只是在solidity中使用json字符串作为数据,因为我需要操作地址,我不想在solidity中处理连接,因为这很麻烦。
我已经用多种方法在谷歌上搜索过这个问题,我甚至问过ChatGPT和Bard,但无论我做什么,我都找不到一种方法来将数据编码为Python中的结构体。要么我把元素分开,像eth_abi.encode(['string', 'address'], [struct['data'], struct['issuer']])
一样编码,这在可靠性上相当于做abi.encode(myStruct.data, myStruct.issuer)
。这对我来说不起作用,因为它产生的字节集与直接编码结构体(其中包含有关类型的额外数据)不同。在我的生产代码中,myStruct要复杂得多,有很多成员,这些成员可能会随着时间的推移而变化,所以我宁愿不必手动解包其成员来编码它,并在每次想要解码时重建结构。
无论我做什么,我都找不到一种方法来做像encode(["string", "address"], [myStruct])
这样的事情。我也试过:
myStruct = {
'data': 'Hello',
'issuer': '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4' # Example address
}
struct_types = {
'data': 'string',
'issuer': 'address'
}
struct_types2 = {
'string': 'data',
'address': 'issuer'
}
encode(struct_types, myStruct)
encode([struct_types], myStruct)
encode(struct_types, [myStruct])
encode([struct_types], [myStruct])
encode(struct_types2, myStruct)
encode([struct_types2], myStruct)
encode(struct_types2, [myStruct])
encode([struct_types2], [myStruct])
上面没有一个做我需要的。我开始怀疑这是否可能,但它不应该那么难,solidity很容易做到,如果你发现在python中没有等效的方法来做这件事,你会感到惊讶,因为你可以很容易地单独编码元素,但我似乎找不到一种方法来添加“结构”部分到编码中,就像abi.encode(myStruct)
和abi.encode(myStruct.data, myStruct.issuer)
在solidity中一样。
1条答案
按热度按时间0x6upsns1#
解决方案比我想象的要简单得多
它确实依赖于dict的顺序与
encode
的第一个参数中的元组相同。Solidity中的struct
与tuple
相同,就编码/解码而言。eth_abi
确实需要将所有内容分解为各个值。如果你有一个额外的myStructTypes
可用,你可以使用类似这样的参数来表示encode
的第一个参数: