ethereum - Solidity:如何将 bytes32 表示为字符串

标签 ethereum solidity

这在其他语言中可能很简单,但我不知道如何在 Solidity 中做到这一点。
我有一个 bytes32像这样0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712 .
我不想将字节转换为字符串,而只想将整个内容表示为字符串,例如“0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712”。
如何在 Solidity 中做到这一点?
更新:
为什么我需要这样做:基本上我连接到一个预言机,它在链下做一些工作,最后上传一个文件到 IPFS。我需要将内容标识符从 oracle 获取到我的契约(Contract)中。 oracle只能发bytes32作为回应,所以我将其转换为 multihash并且只发送 digestbytes32从预言机到合约。
到目前为止一切顺利,我可以在我的合约中重新创建多重哈希。问题是在此之后我创建了一个 ERC721 (NFT) token ,我必须在元数据中存储一些对 IPFS 文件的引用,它只能在 string 中。格式。这就是我目前被困的地方。

最佳答案

虽然@Burt 的答案看起来是正确的(虽然没有对其进行测试),但有一种更有效的方法来解决相同的任务:

function toHex16 (bytes16 data) internal pure returns (bytes32 result) {
    result = bytes32 (data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 |
          (bytes32 (data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64;
    result = result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 |
          (result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32;
    result = result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 |
          (result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16;
    result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 |
          (result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8;
    result = (result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4 |
          (result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8;
    result = bytes32 (0x3030303030303030303030303030303030303030303030303030303030303030 +
           uint256 (result) +
           (uint256 (result) + 0x0606060606060606060606060606060606060606060606060606060606060606 >> 4 &
           0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) * 7);
}

function toHex (bytes32 data) public pure returns (string memory) {
    return string (abi.encodePacked ("0x", toHex16 (bytes16 (data)), toHex16 (bytes16 (data << 128))));
}
此代码产生大写输出。对于小写输出,只需将代码中的 7 更改为 39。
说明
这个想法是使用二进制操作一次处理 16 个字节。toHex16 函数将表示为 bytes16 值的 16 字节序列转换为表示为 bytes32 值的 32 个十六进制数字序列。 toHex 函数将 bytes32 值拆分为两个 bytes16 块,通过 toHex16 函数将每个块转换为十六进制表示,最后使用 0x 函数将 abi.encodePacked 前缀与转换后的块连接起来。
最复杂的部分是 toHex16 函数的工作原理。让我们逐句解释一下。
第一句话:
result = bytes32 (data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 |
      (bytes32 (data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64;
这里我们将输入的最后 64 位右移 64 位,基本上是:
0123456789abcdeffedcba9876543210
\______________/\______________/
       |               |
       |               +---------------+
 ______V_______                  ______V_______
/              \                /              \
0123456789abcdef0000000000000000fedcba9876543210
第二句话:
result = result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 |
      (result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32;
这里我们将两个 64 位块的最后 32 位向右移动 32 位:
0123456789abcdef0000000000000000fedcba9876543210
\______/\______/                \______/\______/
   |       |                       |       |
   |       +-------+               |       +-------+
 __V___          __V___          __V___          __V___
/      \        /      \        /      \        /      \
012345670000000089abcdef00000000fedcba980000000076543210
下一句:
result = result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 |
      (result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16;
做:
012345670000000089abcdef00000000fedcba980000000076543210
\__/\__/        \__/\__/        \__/\__/        \__/\__/
 |   |           |   |           |   |           |   |
 |   +---+       |   +---+       |   +---+       |   +---+
 V_      V_      V_      V_      V_      V_      V_      V_
/  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \
012300004567000089ab0000cdef0000fedc0000ba980000765400003210
下一个:
result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 |
      (result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8;
做:
012300004567000089ab0000cdef0000fedc0000ba980000765400003210
\/\/    \/\/    \/\/    \/\/    \/\/    \/\/    \/\/    \/\/
| |     | |     | |     | |     | |     | |     | |     | |
| +-+   | +-+   | +-+   | +-+   | +-+   | +-+   | +-+   | +-+
V   V   V   V   V   V   V   V   V   V   V   V   V   V   V   V
/\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\
01002300450067008900ab00cd00ef00fe00dc00ba00980076005400320010
这个系列的最后一句话有点不同:
result = (result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4 |
      (result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8;
它将奇数半字节向右移动 4 位,偶数半字节向右移动 8 位:
01002300450067008900ab00cd00ef00fe00dc00ba00980076005400320010
|\  |\  |\  |\  |\  |\  |\  |\  |\  |\  |\  |\  |\  |\  |\  |\
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
 V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
000102030405060708090a0b0c0d0e0f0f0e0d0c0b0a09080706050403020100
因此,初始数据的所有半字节每字节分配一个。
现在对于每个字节 x 我们需要进行以下转换:
x` = x < 10 ? '0' + x : 'A' + (x - 10)
让我们稍微重写一下这个公式:
x` = ('0' + x) + (x < 10 ? 0 : 'A' - '0' - 10)
x` = ('0' + x) + (x < 10 ? 0 : 1) * ('A' - '0' - 10)
请注意, (x < 10 ? 0 : 1) 可以计算为 ((x + 6) >> 4) ,因此我们有:
x` = ('0' + x) + ((x + 6) >> 4) * ('A' - '0' - 10)
x` = (0x30 + x) + ((x + 0x06) >> 4) * 7
最后声明:
result = bytes32 (0x3030303030303030303030303030303030303030303030303030303030303030 +
       uint256 (result) +
       (uint256 (result) + 0x0606060606060606060606060606060606060606060606060606060606060606 >> 4 &
       0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) * 7);
基本上对每个字节执行上述计算。这
0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F
需要右移后的掩码将原始公式中右移“丢弃”的位清零。
顺便说一句,最好在 https://ethereum.stackexchange.com/ 提出这样的问题

关于ethereum - Solidity:如何将 bytes32 表示为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67893318/

相关文章:

即使我有足够的余额,以太坊 ganache 仍失败并显示 "Exceeds block gas limit"

bitcoin - Hyperledger Fabric 如何避免死循环?

solidity - Require() 函数在下面的代码中无法正常工作

javascript - MetaMask - RPC 错误 : Error: [ethjs-query] while formatting outputs from RPC

blockchain - abi.encodePacked(...) 和 sha256(..) 如何在 Solidity 中工作?

ethereum - 如何计算 Uniswap V3 中添加流动性的存款金额

ethereum - Solidity中的HashSet数据结构

next.js - 在 NextJS 应用程序中导入 web3 时出现 Netlify 构建错误 - 'Error: Can' t 解析 'electron' ...'

ethereum - Ganache(来自 Truffle)在启动时挂起

solidity - 如何在 solidity 中将字节转换为 uint256