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

2023-11-22

这在其他语言中可能很简单,但我不知道如何在 Solidity 中做到这一点。
我有一个bytes32像这样0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712.

I don't想要将字节转换为字符串,而不是我只想将整个内容表示为字符串,例如“0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712”。
在 Solidity 中如何做到这一点?

Update:
为什么我需要这样做:基本上我连接到一个预言机,它在链外执行一些工作,最后将文件上传到 IPFS。我需要从预言机将内容标识符添加到我的合约中。预言机只能发送bytes32作为响应,所以我将其转换为多哈希并仅发送digest as bytes32从预言机到合约。
到目前为止一切顺利,我可以在合约中重新创建多重哈希。问题是,在此之后我创建了一个ERC721(NFT)令牌,我必须在元数据中存储对 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 个字节。

The toHex16函数将 16 个字节的序列转换为bytes16值转换为 32 个十六进制数字的序列,表示为bytes32价值。这toHex函数拆分abytes32值一分为二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;

does:

012345670000000089abcdef00000000fedcba980000000076543210
\__/\__/        \__/\__/        \__/\__/        \__/\__/
 |   |           |   |           |   |           |   |
 |   +---+       |   +---+       |   +---+       |   +---+
 V_      V_      V_      V_      V_      V_      V_      V_
/  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \
012300004567000089ab0000cdef0000fedc0000ba980000765400003210

下一个:

result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 |
      (result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8;

does:

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/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Solidity:如何将 bytes32 表示为字符串 的相关文章

随机推荐

  • 从 String[] 到 F# List 的高效转换

    我是从 C 背景转向 F 的 在不同的列表和集合方面有点落后 我最近遇到一个情况 我需要从 string 到 T 列表 我最终使用列表理解来进行转换 let lines File ReadAllLines C LinesOText txt
  • C++ 意外整数提升

    我最近正在编写一些实际上应该测试其他代码的代码 我偶然发现了一个令人惊讶的整数提升案例 这是最小的测试用例 include
  • 如何让机器人提及频道?

    我正在发表欢迎信息 但我似乎无法说出规则频道 我希望机器人说出 rules 并执行它 以便您可以单击它进入规则频道 我知道您可以对普通用户执行此操作 但我想用我的机器人执行此操作 每次尝试都无法像普通播放器一样点击 我尝试过 rules 和
  • UITableView 多选

    如何将 UITableView 添加到基于视图的应用程序中 用户将点击多个单元格 它将被选中 就像时钟应用程序的名为 重复 的 新闹钟 设置 时钟 gt 闹钟 gt gt 重复 如何获取数组中所有选定的单元格 对于多项选择 请添加以下行vi
  • git:// 协议被公司阻止,我该如何解决这个问题?

    尝试类似的事情git clone git github com ry node git不会起作用 它会导致 Initialized empty Git repository in home robert node git github co
  • python 执行器从完成回调中生成任务(递归提交任务)

    我正在尝试根据已完成的任务结果提交进一步的任务 with concurrent futures ThreadPoolExecutor as executor future executor submit my task def callba
  • 将字符串转换为 JSONArray(不是 gson 中的 JsonArray)[重复]

    这个问题在这里已经有答案了 如何正确地将这个字符串转换为 jsonArray myArray id 1 att1 14 2 att2 false id 2 att1 13 2 att2 false id 3 att1 13 att2 fal
  • 有没有办法根据字符串相似性过滤 django 查询集(la python difflib)?

    我需要将冷线索与我们客户的数据库进行匹配 潜在客户大量来自第三方提供商 数千条记录 销售人员要求我们 用他们的话说 过滤掉我们的客户 这样他们就不会试图向既定客户出售我们的服务 显然 线索中存在拼写错误 查尔斯变成了查理 约瑟夫变成了乔 等
  • 注销和登录后任务计划程序无法显示应用程序的 GUI(无论用户是否登录都运行)

    我有一个 GUI 应用程序 我希望它在重新启动 注销 Windows 计算机后自动运行 以下是我使用 Windows 任务计划程序的方法 首先运行命令创建任务 c Windows System32 schtasks exe Create T
  • 在 anaconda 环境中使用 pyinstaller

    我有一个非常简单的应用程序python v 3 6 我想使用 pyinstaller 冻结它 我使用 anaconda 创建的环境制作了该应用程序 并在那里安装了我需要的软件包 youtube dl 我需要有关如何使用我创建的环境 其中包含
  • 这是在ansible中更改conf文件配置的最佳方法

    最初我使用了一个makefile将我的应用程序部署在linux 我有各种sed用于替换 PHP 上传文件大小 帖子大小 日志文件位置等变量的命令 现在我正在转向ansible 我知道我可以复制这些文件 但是如何更改conf文件 就像我只是想
  • React JS/Typescript 中的空合并运算符[重复]

    这个问题在这里已经有答案了 我们有 Null 合并运算符 NET我们可以使用如下 string postal code address postal code 我们可以在 React JS 中做同样的事情吗 我发现我们可以用 运算符来做 i
  • 具有更多模板参数的部分专业化

    部分特化是否允许拥有比主模板更多的模板参数 我的理解是 部分特化必须具有与主模板更少或相同数量的模板参数 我正在阅读 C 模板 第 2 版 其中第 5 4 节 第 72 页 提到 template
  • Python重命名文件从csv文件读取名称

    你好 我一直在努力适应this满足我的需要 但我只是 python 的新手 我有一个包含多个列和行的 csv 文件 重要的列是 1 文件的旧名称 2 文件的新名称 所以我需要转到其中的目录csv 文件中列出的文件并将它们重命名为第 2 列的
  • 在 Android 7(API 级别 24)中,我的应用程序不允许将手机静音(将铃声模式设置为静音)

    我有一个应用程序 通过使用 AudioManager 并将铃声模式设置为静音 使用以下代码将手机静音 AudioManager audioManager AudioManager context getSystemService Conte
  • 奇怪的类声明

    在 Qt 的 qrect h 中 我发现类声明是这样开始的 class Q CORE EXPORT QRect 正如你所看到的 class 关键字后面有两个标识符 我该如何理解这一点 谢谢 Q CORE EXPORT is 扩展为不同值的宏
  • PDO - 获取当前插入的ID

    query INSERT INTO news VALUES NULL param1 param2 stmt pdo gt prepare query params array param1 gt p title param2 gt p bo
  • 如何在指定节点TOC(.NET)上打开CHM文件

    您好 我需要在 NET 应用程序中实现上下文帮助 我有 chm 文件 我正在寻找在标准查看器中打开它的可能性 并突出显示目录 或索引条目 所需的主题 知道如何存档吗 EDIT 也许用于打开 CHM 文件的 MS 应用程序有一些允许存档的命令
  • 使用 Pylint 显示错误和警告

    所以我开始使用 Pylint 但由于我使用制表符而不是空格 它给了我警告 也因为一些方法来自基类 它们也是 GalleryUi 的实例 没有 setModel 成员 而它有 QAbstractTableModel作为基类 那么我如何设置 P
  • Solidity:如何将 bytes32 表示为字符串

    这在其他语言中可能很简单 但我不知道如何在 Solidity 中做到这一点 我有一个bytes32像这样0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712 I