Ethereum 如何从交易凭证重新创建原始交易,以验证v、r、s签名?

Ethereum 如何从交易凭证重新创建原始交易,以验证v、r、s签名?,ethereum,web3,Ethereum,Web3,我正在尝试验证以太坊交易 以下是我的步骤。 1.进行交易 2.使用eth.getTransaction()获取事务 3.使用ethereumjs tx重新创建事务 但有时我无法验证交易 案例1:私有测试网上的简单发送以太事务 获取事务详细信息 { blockHash: "0x2125539ac67b4569828737ffb1731048e00121954f0555d0dc96af665071a62b", blockNumber: 24615, from: "0x81c24515cd

我正在尝试验证以太坊交易

以下是我的步骤。
1.进行交易
2.使用eth.getTransaction()获取事务
3.使用ethereumjs tx重新创建事务

但有时我无法验证交易

案例1:私有测试网上的简单发送以太事务

  • 获取事务详细信息

    { blockHash: "0x2125539ac67b4569828737ffb1731048e00121954f0555d0dc96af665071a62b", blockNumber: 24615, from: "0x81c24515cdf1a4b68f34e3e2824d44b28d00f010", gas: 90000, gasPrice: 18000000000, hash: "0x9e4ce952759eae925173c6c6055c1afe577a48462caacd8d4fb742e911eae053", input: "0x", nonce: 0, r: "0x826b5348acbec72bab39c5debc8493e34d23b351bc7c20ded25d2a4eed736093", s: "0x2a87e18b22c76d61ce9d6a4d56949afa025f1611aa6bb9fd9d6c502d61f7361b", to: "0x487f5eea74ea5f3e94093d8b0501f1d2b0d5310a", transactionIndex: 0, v: "0x10f469", value: 1000000000000000000 } { 区块散列:“0x2125539ac67b4569828737ffb1731048e00121954f0555d0dc96af665071a62b”, 区块编号:24615, 发件人:“0x81c24515cdf1a4b68f34e3e2824d44b28d00f010”, 煤气:90000, 加斯普里斯:180亿, 散列:“0x9e4ce952759eae925173c6c6055c1afe577a48462caacd8d4fb742e911eae053”, 输入:“0x”, 零时:, r:“0x826b5348acbec72bab39c5debc8493e34d23b351bc7c20ded25d2a4eed736093”, s:“0x2A87E18B22C76D61CE9D6A4D6949AFA025F1611AA6B9FD9D6C502D61F7361B”, 致:“0x487F5EEA74EA5F3E94093D8B051F1D2B0D5310A”, transactionIndex:0, v:“0x10f469”, 价值:10000000000000000 }
  • 然后使用事务详细信息和ethereumjs-tx创建一个transaction

    const EthereumTx = require('ethereumjs-tx') const test_arr1 = { nounce: "0x"+parseInt(0, 10).toString(16), gasPrice: "0x"+parseInt(18000000000, 10).toString(16), gasLimit: "0x"+parseInt(90000, 10).toString(16), to: '0x487f5eea74ea5f3e94093d8b0501f1d2b0d5310a', value: "0x"+parseInt(1000000000000000000, 10).toString(16), data: '0x', v: '0x10f469', r: '0x826b5348acbec72bab39c5debc8493e34d23b351bc7c20ded25d2a4eed736093', s: '0x2a87e18b22c76d61ce9d6a4d56949afa025f1611aa6bb9fd9d6c502d61f7361b' } const tx = new EthereumTx(test_arr1); const recoveredAddress = "0x"+tx.getSenderAddress().toString('hex') recoveredAddress is 0x81c24515cdf1a4b68f34e3e2824d44b28d00f010 which is correct const EthereumTx = require('ethereumjs-tx') const test_arr2 = { nounce: "0x"+parseInt(129, 10).toString(16), gasPrice: "0x"+parseInt(18000000000, 10).toString(16), gasLimit: "0x"+parseInt(309588, 10).toString(16), to: '0xad5e2d5cb93f098423597c891d2f1ed35f904ca1', value: "0x", data: '0x03e63bdb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000890000000b000000012e507fe5cce2f11c2a520a265f593c08372834fec925f84bbe5a72793ec5096d03fd11970afed8b767adfed60caf3f0c1de0dbda06d48f9afc3661717dbf85641b3f011114d3a41bf16a8d8cc33769aba2abe14efb14487295c80da13b3e333707202d1bdea56f75616202491b4bcc437b6a5b7a79284a08e28bcd0a90e3d87bf10000000000000000000000000000000000000000000000', v: '0x2a', r: '0xdd4fe550275bd35ffd4babf6ac3578575594011f027923046da78a7b179ffb66', s: '0x2584e1f3f36185f6cd9358146f2479dde41dbb85ced5859c845a065cb5bdc42b', chainId: 3 } const tx2 = new EthereumTx(test_arr2); const recoveredAddress = "0x"+tx2.getSenderAddress().toString('hex') recoveredAddress is 0x9c9d4315824275f545b2e96026a7075f75125b9b which is NOT correct. It should be 0x0d6883a0e7071513c7d90a27bf2715bc71ecf107 常量EthereumTx=require('ethereumjs-tx') 常数测试\u arr1={ 名词:“0x”+parseInt(0,10).toString(16), 加斯普里斯:“0x”+parseInt(18000000000,10)。toString(16), gasLimit:“0x”+parseInt(90000,10).toString(16), 至:“0x487F5EEA74EA5F3E94093D8B051F1D2B0D5310A”, 值:“0x”+parseInt(10000000000000000,10).toString(16), 数据:“0x”, v:'0x10f469', r:'0x826b5348acbec72bab39c5debc8493e34d23b351bc7c20ded25d2a4eed736093', s:'0x2A87E18B22C76D61CE9D6A4D6949AFA025F1611AA6B9FD9D6C502D61F1F7361B' } const tx=新以太坊tx(测试1); const recoveredAddress=“0x”+tx.getSenderAddress().toString('hex') 恢复的地址是0x81c24515cdf1a4b68f34e3e2824d44b28d00f010,这是正确的
  • 案例2:ropsten testnet中的智能合约

  • 获取事务详细信息

    { blockHash: "0xead9335751dbdb4a874b2bb48ac15ddafbec6f2ba55a5932bf6ec1a0475166e7", blockNumber: 3026266, from: "0x0d6883a0e7071513c7d90a27bf2715bc71ecf107", gas: 309588, gasPrice: 18000000000, hash: "0xe69d8b108af59198857dd5b045769748dbe1ca3ad9bba7dbbb512643b9d85b5a", input: "0x03e63bdb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000890000000b000000012e507fe5cce2f11c2a520a265f593c08372834fec925f84bbe5a72793ec5096d03fd11970afed8b767adfed60caf3f0c1de0dbda06d48f9afc3661717dbf85641b3f011114d3a41bf16a8d8cc33769aba2abe14efb14487295c80da13b3e333707202d1bdea56f75616202491b4bcc437b6a5b7a79284a08e28bcd0a90e3d87bf10000000000000000000000000000000000000000000000", nonce: 129, r: "0xdd4fe550275bd35ffd4babf6ac3578575594011f027923046da78a7b179ffb66", s: "0x2584e1f3f36185f6cd9358146f2479dde41dbb85ced5859c845a065cb5bdc42b", to: "0xad5e2d5cb93f098423597c891d2f1ed35f904ca1", transactionIndex: 0, v: "0x2a", value: 0 } { 区块散列:“0xEAD9335751DBB4A874B2BB48AC15DDAFBEC6F2BA55A5932BF6EC1A0475166E7”, 区块编号:3026266, 发件人:“0x0d6883a0e7071513c7d90a27bf2715bc71ecf107”, 煤气:309588, 加斯普里斯:180亿, 散列:“0xe69d8b108af59198857dd5b045769748dbe1ca3ad9bba7dbbb512643b9d85b5a”, 输入:"0x03E63BDB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000890000000B000000012E507FE5CE2F1C2A520A265F593C08372834FEC925F54BBE5A72793EC5096D03FD11970AFED8B767ADFED60CAF3F00DBDA06D48F9AFC661717DBF85641B3F011114D3A41BF16A8D8CC339ABEA14EFB14487C80B333707202D1BDEA56F75616202491B4BCC437B6A5B7A79284A08E28BCD0A90E3D87BF1000000000000000“, 暂时:129, r:“0xDD4FE550275BD35FFD4BABF6AC357857559401F027923046DA78A7B179FFB66”, s:“0x2584e1f3f36185f6cd9358146f2479dde41dbb85ced5859c845a065cb5bdc42b”, 致:“0xad5e2d5cb93f098423597c891d2f1ed35f904ca1”, transactionIndex:0, v:“0x2a”, 数值:0 }
  • 然后使用事务详细信息和ethereumjs-tx创建一个transaction

    const EthereumTx = require('ethereumjs-tx') const test_arr1 = { nounce: "0x"+parseInt(0, 10).toString(16), gasPrice: "0x"+parseInt(18000000000, 10).toString(16), gasLimit: "0x"+parseInt(90000, 10).toString(16), to: '0x487f5eea74ea5f3e94093d8b0501f1d2b0d5310a', value: "0x"+parseInt(1000000000000000000, 10).toString(16), data: '0x', v: '0x10f469', r: '0x826b5348acbec72bab39c5debc8493e34d23b351bc7c20ded25d2a4eed736093', s: '0x2a87e18b22c76d61ce9d6a4d56949afa025f1611aa6bb9fd9d6c502d61f7361b' } const tx = new EthereumTx(test_arr1); const recoveredAddress = "0x"+tx.getSenderAddress().toString('hex') recoveredAddress is 0x81c24515cdf1a4b68f34e3e2824d44b28d00f010 which is correct const EthereumTx = require('ethereumjs-tx') const test_arr2 = { nounce: "0x"+parseInt(129, 10).toString(16), gasPrice: "0x"+parseInt(18000000000, 10).toString(16), gasLimit: "0x"+parseInt(309588, 10).toString(16), to: '0xad5e2d5cb93f098423597c891d2f1ed35f904ca1', value: "0x", data: '0x03e63bdb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000890000000b000000012e507fe5cce2f11c2a520a265f593c08372834fec925f84bbe5a72793ec5096d03fd11970afed8b767adfed60caf3f0c1de0dbda06d48f9afc3661717dbf85641b3f011114d3a41bf16a8d8cc33769aba2abe14efb14487295c80da13b3e333707202d1bdea56f75616202491b4bcc437b6a5b7a79284a08e28bcd0a90e3d87bf10000000000000000000000000000000000000000000000', v: '0x2a', r: '0xdd4fe550275bd35ffd4babf6ac3578575594011f027923046da78a7b179ffb66', s: '0x2584e1f3f36185f6cd9358146f2479dde41dbb85ced5859c845a065cb5bdc42b', chainId: 3 } const tx2 = new EthereumTx(test_arr2); const recoveredAddress = "0x"+tx2.getSenderAddress().toString('hex') recoveredAddress is 0x9c9d4315824275f545b2e96026a7075f75125b9b which is NOT correct. It should be 0x0d6883a0e7071513c7d90a27bf2715bc71ecf107 常量EthereumTx=require('ethereumjs-tx') 常数测试_arr2={ 名词:“0x”+parseInt(129,10)。toString(16), 加斯普里斯:“0x”+parseInt(18000000000,10)。toString(16), gasLimit:“0x”+parseInt(309588,10).toString(16), 至:“0xad5e2d5cb93f098423597c891d2f1ed35f904ca1”, 值:“0x”, 数据:“0x03E63BDB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000890000000B000000012E507FE5CE2F1C2A520A265F593C0C08372834FEC925F85BBE5A72793EC5096D03FD11970AFED8BF767ADFED60CAF3F00CF6D4F9AFC661717DBF85629541B3F011114D3A41BF16A8D8CC33769ABEA14EFB14487C80DA13E333707202D1BDEA56F7566202491B4BCC437B6A5B7A79284A08E28BCD0A90E3D87BF1000000000000000', v:'0x2a', r:'0xDD4FE550275BD35FFD4BABF6AC357857559401F027923046DA78A7B179FFB66', s:'0x2584e1f3f36185f6cd9358146f2479dde41dbb85ced5859c845a065cb5bdc42b', 链号:3 } 常数tx2=新以太坊TX(测试2); const recoveredAddress=“0x”+tx2.getSenderAddress().toString('hex') 恢复的地址为0x9C9D431582475F545B2E96026A7075F75125B9B,该地址不正确。该地址应为0x0d6883a0e7071513c7d90a27bf2715bc71ecf107
  • 为什么呢? 如何正确地重新创建原始事务

    或者是否有任何其他方式验证带有v、r、s签名的交易


    提前感谢。

    如果您使用的是web3js v1.0,您只需使用即可。他们文档中的示例:

    web3.eth.accounts.recover({
        messageHash: '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655',
        v: '0x1c',
        r: '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd',
        s: '0x6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a029'
    })
    > "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23"
    
    另一个选项是,您可以在使用Solidity的
    ecrecover()
    的合同中调用
    视图
    函数

    ecrecover(字节32哈希,uint8 v,字节32 r,字节32 s)返回(地址):从椭圆曲线签名中恢复与公钥关联的地址,错误时返回零

    例如:

    function verify(bytes prefix, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) external pure returns(address) {
      bytes32 prefixedHash = keccak256(prefix, msgHash);
      return ecrecover(prefixedHash, v, r, s);
    }
    

    但是,您必须小心使用前缀。不同的客户端可能使用不同的前缀。例如,
    geth
    使用
    prefix=“\x19Ethereum签名消息:\n32”对事务进行签名“

    谢谢您的回复。在这种情况下,msgHash是什么?看起来hash和blockHash不是一个…而是你签名的消息的sha3散列。顺便说一句,你最初的方法也没有什么问题。我运行了您的签名发送并返回了正确的地址:>signed.getSenderAddress().toString('hex');'0d6883a0e7071513c7d90a27bf2715bc71ecf107'。也许是因为你在你的对象中拼错了“nonce”?是的,你是对的!这是因为我的打字错误。谢谢