Web3.js签名消息方法异常:React简易示例问题排查
签名验证地址不一致的问题修复
你的核心问题是签名和验证时对消息的处理逻辑不匹配,导致哈希值不一致,最终恢复出的签名地址和原地址对不上:
web3.eth.sign是以太坊钱包签名的标准方法,它会自动给传入的消息添加固定前缀:"\x19Ethereum Signed Message:\n" + 消息长度,然后再计算哈希进行签名。但你在签名时提前对原消息做了sha3哈希,相当于让web3.eth.sign对哈希后的结果又加了前缀再哈希,签名的内容和验证时处理的内容完全不匹配。- 验证环节你把原消息转成Hex再哈希,完全没遵循签名时的标准前缀规则,自然无法正确恢复出签名地址。
修正后的代码
import './App.css'; import Web3 from "web3/dist/web3.min.js" import React, { useState, useEffect } from 'react'; function App() { const [address, setAddress] = useState(''); const [message, setMessage] = useState('ciao'); const [signature, setSignature] = useState(''); const [isValid, setIsValid] = useState(false); const [web3, setWeb3] = useState(null); useEffect(() => { async function getWeb3() { if (window.ethereum) { const web3 = new Web3(window.ethereum); await window.ethereum.enable(); const accounts = await web3.eth.getAccounts(); setAddress(accounts[0]); setWeb3(web3); } } getWeb3(); }, []); const signMessage = async () => { // 直接传入原始消息,让web3.eth.sign按照标准流程处理前缀和哈希 const signature = await web3.eth.sign(message, address); setSignature(signature); }; const verifyMessage = async () => { // 直接用原始消息和签名调用recover,方法会自动处理标准前缀 const signer = web3.eth.accounts.recover(message, signature); // 注意地址大小写问题,统一转成小写比较 const isMatch = signer.toLowerCase() === address.toLowerCase(); setIsValid(isMatch); console.log(isMatch ? "验证通过" : "验证失败"); }; return ( <div className="App"> <header className="App-header"> <p>Sign Message: {message}</p> <button onClick={signMessage}>Sign</button> <p>Signature: {signature}</p> <button onClick={verifyMessage}>Verify</button> <p>Is Valid: {isValid ? 'True' : 'False'}</p> </header> </div> ); } export default App;
关键修正点
- 签名函数:移除了提前计算
messageHash的步骤,直接传入原始消息给web3.eth.sign,让它按照以太坊签名标准处理前缀和哈希。 - 验证函数:直接用原始消息和签名调用
web3.eth.accounts.recover,该方法内部会自动添加标准前缀并计算正确的哈希,恢复出签名地址。同时增加了地址大小写统一比较,避免因地址大小写格式不同导致的匹配失败。
内容的提问来源于stack exchange,提问作者xitalianx
相关产品推荐
相关产品推荐

