Solidity 和 web3 sha3
Posted
技术标签:
【中文标题】Solidity 和 web3 sha3【英文标题】:Solidity and web3 sha3 【发布时间】:2021-11-10 20:10:03 【问题描述】:我尝试在我的智能合约中使用种子对 tokenId 进行哈希处理。为简单起见并避免其他错误,我暂时将种子放在一边。我基本上只是想在我的合同上散列一个数字并在我的 javascript 代码上散列相同的数字并接收相同的输出。 代码在 Solidity 上看起来像这样:
function _tokenURI(uint256 tokenId) internal view returns (string memory)
string memory currentBaseURI = _baseURI();
bytes32 hashedToken = keccak256(abi.encodePacked(tokenId));
return
bytes(currentBaseURI).length > 0
? string(abi.encodePacked(currentBaseURI, hashedToken, baseExtension))
: "";
这也会导致客户端出现错误invalid codepoint at offset
。为了解决这个问题,我尝试使用这些函数将 bit32 转换为字符串
function _bytes32ToString(bytes32 _bytes32)
private
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) private pure returns (bytes1)
if (_uint8 < 10)
return bytes1(_uint8 + 48);
else
return bytes1(_uint8 + 87);
虽然我不确定这是否等效。前端代码如下:
const hashed = web3.utils.soliditySha3(
type: "uint256", value: tokenId
);
为了获得完全相同的输出,我需要进行哪些更改? invalid codepoint at offset
是什么意思?
【问题讨论】:
【参考方案1】:您收到invalid codepoint
错误,因为您在调用abi.encodePacked(currentBaseURI, hashedToken, baseExtension))
时混合了字符串和字节数据。
当 Javascript 从合约中获取返回值时,它需要一个 UTF8 字符串,但在您的 hashedToken 中,您的字节值对于 UTF8 编码的字符串无效。
这种错误可能是“间歇性的”。它可能仅在某些情况下发生。您很幸运在开发过程中而不是在生产环境中看到它。
如何解决?
您将哈希结果转换为字符串是正确的。 在这个answer 中有另一种方法可以做到这一点,它只使用按位运算来使用更少的气体。
要在 Javascript 中转换十六进制值,您可以使用 web3.utils.hexToNumberString()。
【讨论】:
【参考方案2】:也许问题是 tokenId 不是 uint256 或 Web3,Solidity 版本?我用 Remix IDE 做了一些测试,得到了相同的结果。 Solidity 代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Hash
function getHashValue_1() public view returns(bytes32)
return keccak256(abi.encodePacked(uint256(234)));
// bytes32: 0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2
function getHashValue_3() public view returns(bytes32)
return keccak256(abi.encodePacked(uint256(10),string('StringSecretValue')));
// bytes32: 0x5938b4caf29ac4903ee34628c3dc1eb5c670a6bd392a006d0cb91f1fc5db3819
JS代码:
(async () =>
try
console.log('Web3 version is '+ Web3.version);
// Web3 version is 1.3.0
let theValueYouNeed = web3.utils.soliditySha3("234");
theValueYouNeed = web3.utils.soliditySha3(type: 'uint256', value: '234');
theValueYouNeed = web3.utils.soliditySha3(t: 'uint256', v: '234');
// above hashed value is 0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2
console.log('Hashed value 1 is '+theValueYouNeed);
theValueYouNeed = web3.utils.soliditySha3(t: 'uint256', v: '10',t: 'string', v: 'StringSecretValue');
console.log('Hashed value 2 is '+theValueYouNeed);
// above hashed value is 0x5938b4caf29ac4903ee34628c3dc1eb5c670a6bd392a006d0cb91f1fc5db3819
catch (e)
console.log(e.message)
)()
我不确定,但 invalid codepoint at offset 应该意味着 a designated value does not fall within the range or set of allowed values... 所以也许 tokenId 有问题,你可以做一些测试使用硬编码值?
【讨论】:
以上是关于Solidity 和 web3 sha3的主要内容,如果未能解决你的问题,请参考以下文章
Solidity、solc、web3.js、Ganache 版本组合目前正在使用啥