如何在python中编码一个solidity结构体?

xoshrz7s  于 2023-05-21  发布在  Python
关注(0)|答案(1)|浏览(99)

我在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中一样。

0x6upsns

0x6upsns1#

解决方案比我想象的要简单得多

from eth_utils import keccak
from eth_abi import encode

myStruct = {
    'data': 'Hello',
    'issuer': '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4'  # Example address
}

def getHash(struct):
    return keccak(encode(['(string,address)'], [tuple(struct.values())]))

它确实依赖于dict的顺序与encode的第一个参数中的元组相同。Solidity中的structtuple相同,就编码/解码而言。
eth_abi确实需要将所有内容分解为各个值。如果你有一个额外的myStructTypes可用,你可以使用类似这样的参数来表示encode的第一个参数:

str(tuple(myStructTypes.values())).replace(' ', '')

相关问题