From 919d1a27af7e1c197a116f77d383b6b1e887d519 Mon Sep 17 00:00:00 2001 From: ramil Date: Fri, 18 Jun 2021 15:58:02 +0300 Subject: [PATCH] for PoA network like Rinkeby "miner" field is empty due to consensus algorithm https://github.com/ethereum/EIPs/issues/225 Miner address is derivable from "extra" field. Last 65 bytes are miner signature --- src/utils/index.test.ts | 10 +++++++++- src/utils/index.ts | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/utils/index.test.ts b/src/utils/index.test.ts index bd61873..2cab69a 100644 --- a/src/utils/index.test.ts +++ b/src/utils/index.test.ts @@ -1,5 +1,5 @@ import Contract from "../models/contract/contract"; -import {decodeStorageCid, getContractsFromLogs, increaseHexByOne, mhDataToBuffer} from "./index"; +import {decodeStorageCid, extractMinerFromExtra, getContractsFromLogs, increaseHexByOne, mhDataToBuffer} from "./index"; import {EthStorageCid} from "../types"; function dummyContract(address: string): Contract { @@ -90,4 +90,12 @@ describe('utils', () => { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c])); }); + + test('extractMinerFromExtra', () => { + // block 8647996 on Rinkeby + const blockRlp = "f9025ca00a84ebb80b8616551e251a42273bc0860e1db619affc009a7d17b96b8dba6cbaa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0d7ce7224e063acb68e6dd5ba4e0ef90d4c6e61d4e30cdc6b6b5ef5adfc32a8c6a09db0cbfa54f72435c8f15326d01924bb0b9c1aa4ffa1b05eef9e4dbafc4179a1a0e9602d458a57dd10df00ac06b014da188c1bfb2276fd8b39cde58a82cf78169eb9010000020100400000100000400040008800000000100404008000000000004000000000820100000800210000400080200000010000800000000800000000a00240000000820000000800000008008000000000000800000401100000400000001430000000200000000000000010808000200090000000001520080010400000000100000100042000001840000100000080000040104088000000010000040000228000000000400040200000040000040000084000100020000000004000800000104002200000000000000000000047012080010000040040001000000000a00010000000000040000000020000120000000080000006008000100001000000018383f53c8398c5278324527d8460ad1423b861d883010a04846765746888676f312e31362e33856c696e7578000000000000009e5b0e7ed267a159861a0c8a5b982adb1c3d4cfd12cd85eed6389e113ba614e23350342cd4cfeb8ea0d34bcaacadfa1a108be9c204ea5c95642fb8c03b6493df01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"; + const miner = "0x7ffc57839b00206d1ad20c69a1981b489f772031"; + + expect(extractMinerFromExtra(blockRlp)).toEqual(miner); + }); }); diff --git a/src/utils/index.ts b/src/utils/index.ts index 68e9b86..5eb7fde 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,4 @@ -import {rlp, BN} from 'ethereumjs-util'; +import {rlp, BN, fromRpcSig, keccak, ecrecover, addHexPrefix, pubToAddress} from 'ethereumjs-util'; import Contract from "../models/contract/contract"; import {EthStorageCid} from "../types"; @@ -99,4 +99,29 @@ export const decodeExtra = (data: string) => { // eslint-disable-line } return `${str}/${value.toString('utf-8')}` }, ''); +} + +/** + * Returns miner address for PoA networks. Extract it from block extra field + * + * @param blockRlp + */ +export const extractMinerFromExtra = (blockRlp: string): string => { + const blockRlpBuf = mhDataToBuffer(blockRlp); + const decoded: any = rlp.decode(blockRlpBuf); + const extra = decoded[12]; + // last 65 bytes are miner signature + const sig = extra.slice(extra.length - 65); + // convert hex signature to v, r, s format + const signature = fromRpcSig(sig as any as string); + + // to recovery miner address from signature we need to get block hash without this signature + decoded[12] = extra.slice(0, extra.length - 65); + const encodedBlock = rlp.encode(decoded); + const blockHash = keccak(encodedBlock); + console.log(blockHash, signature); + const pub = ecrecover(blockHash, signature.v, signature.r, signature.s) + const address = addHexPrefix(pubToAddress(pub).toString('hex')); + + return address; } \ No newline at end of file