首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Solidity:如何将bytes32表示为字符串

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

Stack Overflow用户
提问于 2021-06-08 19:18:19
回答 2查看 13.7K关注 0票数 8

这在其他语言中可能很简单,但我想不出如何在可靠的情况下做到这一点。

我有一个像这样的bytes320x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712

我不想把字节转换成字符串,我只想把整件事表示成字符串,比如"0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712".

如何才能在坚实的环境下做到这一点?

更新:

为什么我需要这样做:基本上我连接到一个甲骨文,它做一些工作离链,并最终上传一个文件到IPFS。我需要将内容标识符从oracle中输入到我的合同中。oracle只能将bytes32作为响应发送,因此我将其转换为多散列,并将digest作为bytes32从oracle发送到契约。

到目前为止,我可以在我的合同中重新创建多个散列。问题是,在此之后,我创建了一个ERC721 (NFT)令牌,并且必须在元数据中存储对IPFS文件的一些引用,元数据只能是string格式。我现在被困在这里了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-21 10:02:05

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

代码语言:javascript
运行
复制
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个字节序列转换为由32个十六进制数字组成的序列,表示为bytes32值。toHex函数将bytes32值拆分为两个bytes16块,通过toHex16函数将每个块转换为十六进制表示,最后使用abi.encodePacked函数将0x前缀与转换的块连接起来。

最复杂的部分是toHex16函数的工作方式。让我们逐句解释。

第一句:

代码语言:javascript
运行
复制
result = bytes32 (data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 |
      (bytes32 (data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64;

在这里,我们将输入的最后64位向右移动64位,基本完成:

代码语言:javascript
运行
复制
0123456789abcdeffedcba9876543210
\______________/\______________/
       |               |
       |               +---------------+
 ______V_______                  ______V_______
/              \                /              \
0123456789abcdef0000000000000000fedcba9876543210

第二句:

代码语言:javascript
运行
复制
result = result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 |
      (result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32;

在这里,我们将这两个64位块中的最后32位向右移动32位:

代码语言:javascript
运行
复制
0123456789abcdef0000000000000000fedcba9876543210
\______/\______/                \______/\______/
   |       |                       |       |
   |       +-------+               |       +-------+
 __V___          __V___          __V___          __V___
/      \        /      \        /      \        /      \
012345670000000089abcdef00000000fedcba980000000076543210

下一句:

代码语言:javascript
运行
复制
result = result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 |
      (result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16;

是否:

代码语言:javascript
运行
复制
012345670000000089abcdef00000000fedcba980000000076543210
\__/\__/        \__/\__/        \__/\__/        \__/\__/
 |   |           |   |           |   |           |   |
 |   +---+       |   +---+       |   +---+       |   +---+
 V_      V_      V_      V_      V_      V_      V_      V_
/  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \
012300004567000089ab0000cdef0000fedc0000ba980000765400003210

下一个是:

代码语言:javascript
运行
复制
result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 |
      (result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8;

是否:

代码语言:javascript
运行
复制
012300004567000089ab0000cdef0000fedc0000ba980000765400003210
\/\/    \/\/    \/\/    \/\/    \/\/    \/\/    \/\/    \/\/
| |     | |     | |     | |     | |     | |     | |     | |
| +-+   | +-+   | +-+   | +-+   | +-+   | +-+   | +-+   | +-+
V   V   V   V   V   V   V   V   V   V   V   V   V   V   V   V
/\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\
01002300450067008900ab00cd00ef00fe00dc00ba00980076005400320010

本系列的最后一句略有不同:

代码语言:javascript
运行
复制
result = (result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4 |
      (result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8;

它将奇数咬向右边4位,甚至咬8位:

代码语言:javascript
运行
复制
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,我们需要执行以下转换:

代码语言:javascript
运行
复制
x` = x < 10 ? '0' + x : 'A' + (x - 10)

让我们重写一下这个公式:

代码语言:javascript
运行
复制
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),因此我们有:

代码语言:javascript
运行
复制
x` = ('0' + x) + ((x + 6) >> 4) * ('A' - '0' - 10)
x` = (0x30 + x) + ((x + 0x06) >> 4) * 7

最后声明:

代码语言:javascript
运行
复制
result = bytes32 (0x3030303030303030303030303030303030303030303030303030303030303030 +
       uint256 (result) +
       (uint256 (result) + 0x0606060606060606060606060606060606060606060606060606060606060606 >> 4 &
       0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) * 7);

基本上对每个字节执行上述计算。这个

代码语言:javascript
运行
复制
0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F

掩码后的右移是需要零的比特“下降”,由右移位在原来的公式。

顺便说一句,在https://ethereum.stackexchange.com/问这样的问题会更好

票数 23
EN

Stack Overflow用户

发布于 2021-08-11 01:37:17

函数bytes32ToString将bytes32转换为十六进制字符串。

代码语言:javascript
运行
复制
function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) {
    uint8 i = 0;
    bytes memory bytesArray = new bytes(64);
    for (i = 0; i < bytesArray.length; i++) {

        uint8 _f = uint8(_bytes32[i/2] & 0x0f);
        uint8 _l = uint8(_bytes32[i/2] >> 4);

        bytesArray[i] = toByte(_f);
        i = i + 1;
        bytesArray[i] = toByte(_l);
    }
    return string(bytesArray);
}

function toByte(uint8 _uint8) public pure returns (byte) {
    if(_uint8 < 10) {
        return byte(_uint8 + 48);
    } else {
        return byte(_uint8 + 87);
    }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67893318

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档