Hi!
Trying to get information about blocks. For this I use web3 methods. All information displays normaly expect miner address. Tested in rinkeby network
Geth version: 1.8.13
OS & Version: Linux
Miner address should be present in block information
Miner address in null 0x0000000000000000000000000000000000000000
geth --rpc --rpcaddr 0.0.0.0 --rpcvhosts * --rinkeby --syncmode "fast"eth.getBlock(2848394)
{
difficulty: 1,
extraData: "0xd68301080d846765746886676f312e3130856c696e7578000000000000000000773ab2ca8f47904a14739ad80a75b71d9d29b9fff8b7ecdcb73efffa6f74122f17d304b5dc8e6e5f256c9474dd115c8d4dae31b7a3d409e5c3270f8fde41cd8c00",
gasLimit: 7753377,
gasUsed: 1810195,
hash: "0x7004c895e812c55b0c2be8a46d72ca300a683dc27d1d7917ee7742d4d0359c1f",
logsBloom: "0x00000000000000020000000000002000000400000000000000000000000000000000000000000000040000080004000020000010000000000000000000000000000000000000000008000008000000000000000000200000000000000000000000000000020000000000000000000800000000000000804000000010080000000800000000000000000000000000000000000000000000800000000000080000000008000400000000404000000000000000000000000200000000000000000000000002000000000000001002000000000000002000000008000000000020000000000000000000000000000000000000000000000000400000800000000000",
miner: "0x0000000000000000000000000000000000000000",
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000000",
number: 2848394,
parentHash: "0x20350fc367e19d3865be1ea7da72ab81f8f9941c43ac6bb24a34a0a7caa2f3df",
receiptsRoot: "0x6ade4ac1079ea50cfadcce2b75ffbe4f9b14bf69b4607bbf1739463076ca6246",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 6437,
stateRoot: "0x23f63347851bcd109059d007d71e19c4f5e73b7f0862bebcd04458333a004d92",
timestamp: 1534796040,
totalDifficulty: 5353647,
transactions: ["0x7e3bb851fc74a436826d2af6b96e4db9484431811ef0d9c9e78370488d33d4e5", "0x3976fd1e3d2a715c3cfcfde9bd3210798c26c017b8edb841d319227ecb3322fb", "0xd8db124005bb8b6fda7b71fd56ac782552a66af58fe843ba3c4930423b87d1d2", "0x10c1a1ca4d9f4b2bd5b89f7bbcbbc2d69e166fe23662b8db4f6beae0f50ac9fd", "0xaa58a6545677c796a56b8bc874174c8cfd31a6c6e6ca3a87e086d4f66d52858a"],
transactionsRoot: "0xde8d25c0b9b54310128a21601331094b43f910f9f96102869c2e2dca94884bf4",
uncles: []
}
Also found that in "light" mode the same issue appears. Also in "light" mode getTransaction return null instead transaction info.
So, is Miner address is availible only in "full" sync mode?
Kind regards
@APshenkin The miner field in clique algorithm has a different meaning.
Basically, the miner (coinbase) field is used to indicate a target address for new signer proposal or delete signer proposal.
The signer signature has been included in the extraData field so that signer address can be recovered.
For more detail, please take a look at this proposal
@rjl493456442 Thank you for clarifation. But still no luck to get info about signer address. I can't find any example how to do this.Is there a code snippet, how to get info about address from extraData?
Here is a code snippet copied from the clique consensus package. I think it should be similar for you to recover the signer address.
// ecrecover extracts the Ethereum account address from a signed header.
func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
// If the signature's already cached, return that
hash := header.Hash()
if address, known := sigcache.Get(hash); known {
return address.(common.Address), nil
}
// Retrieve the signature from the header extra-data
if len(header.Extra) < extraSeal {
return common.Address{}, errMissingSignature
}
signature := header.Extra[len(header.Extra)-extraSeal:]
// Recover the public key and the Ethereum address
pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature)
if err != nil {
return common.Address{}, err
}
var signer common.Address
copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
sigcache.Add(hash, signer)
return signer, nil
}
@rjl493456442 Thanks a lot.
Trying to reformat it in JS, but no luck
const Web3 = require('web3')
const utils = require('ethereumjs-util')
const BlockHeader = require('ethereumjs-block/header')
const web3 = new Web3(new Web3.providers.HttpProvider('.....'))
const block = web3.eth.getBlock(2848394)
const hashBuff = Buffer.from(block.hash.replace('0x', ''), 'hex')
const dataBuff = Buffer.from(block.extraData.replace('0x', ''), 'hex')
const sig = dataBuff.slice(dataBuff.length - 65)
const signature = {
r: sig.slice(0, 32),
s: sig.slice(32, 64),
v: 27
}
const pub = utils.ecrecover(hashBuff, signature.v, signature.r, signature.s)
const address = utils.pubToAddress(pub).toString('hex')
const checksumAddress = utils.toChecksumAddress(address);
const finalizeAddress = utils.addHexPrefix(checksumAddress);
But address don't match with address on rinkeby.etherscan.io
expected 0xfc18cbc391de84dbd87db83b20935d3e89f5dd91, actual 0x4b3fFff4829cD0c7bE57DE4CFdc7311d27d05166
So several questions more:
const BlockHeader = require('ethereumjs-block/header')
const blockHeader = new BlockHeader({
parentHash: Buffer.from(block.parentHash.replace('0x', ''), 'hex'),
uncleHash: Buffer.from(block.sha3Uncles.replace('0x', ''), 'hex'),
coinbase: Buffer.from(block.miner.replace('0x', ''), 'hex'),
stateRoot: Buffer.from(block.stateRoot.replace('0x', ''), 'hex'),
transactionTrie: Buffer.from(block.transactionsRoot.replace('0x', ''), 'hex'),
receiptTrie: Buffer.from(block.receiptsRoot.replace('0x', ''), 'hex'),
bloom: Buffer.from(block.logsBloom.replace('0x', ''), 'hex'),
difficulty: Buffer.from(block.difficulty.toString(16)),
number: Buffer.from(block.number.toString()),
gasLimit: Buffer.from(block.gasLimit.toString()),
gasUsed: Buffer.from(block.gasUsed.toString()),
timestamp: Buffer.from(block.timestamp.toString()),
extraData: Buffer.from(block.extraData.replace('0x', ''), 'hex'),
mixHash: Buffer.from(block.mixHash.replace('0x', ''), 'hex'),
nonce: Buffer.from(block.nonce.replace('0x', ''), 'hex')
})
const hash = blockHeader.hash()
But this hash doesn't match etherscan hash and still no luck with address recover
expected 0xfc18cbc391de84dbd87db83b20935d3e89f5dd91, actual 0xdA06559899639406677230722047F298C74Db8c2. Maybe I do something wrong?
Other try
const Web3 = require('web3')
const utils = require('ethereumjs-util')
const BlockHeader = require('ethereumjs-block/header')
const web3 = new Web3(new Web3.providers.HttpProvider('......'))
const block = web3.eth.getBlock(2848394)
const hashBuff = Buffer.from(block.hash.replace('0x', ''), 'hex')
const dataBuff = Buffer.from(block.extraData.replace('0x', ''), 'hex')
const sig = dataBuff.slice(dataBuff.length - 65)
const signature = {
r: sig.slice(0, 32),
s: sig.slice(32, 64),
v: 27
}
const sigHash = new BlockHeader({
parentHash: Buffer.from(block.parentHash.replace('0x', ''), 'hex'),
uncleHash: Buffer.from(block.sha3Uncles.replace('0x', ''), 'hex'),
coinbase: Buffer.from(block.miner.replace('0x', ''), 'hex'),
stateRoot: Buffer.from(block.stateRoot.replace('0x', ''), 'hex'),
transactionTrie: Buffer.from(block.transactionsRoot.replace('0x', ''), 'hex'),
receiptTrie: Buffer.from(block.receiptsRoot.replace('0x', ''), 'hex'),
bloom: Buffer.from(block.logsBloom.replace('0x', ''), 'hex'),
difficulty: utils.toBuffer(block.difficulty.toNumber()),
number: utils.toBuffer(block.number),
gasLimit: utils.toBuffer(block.gasLimit),
gasUsed: utils.toBuffer(block.gasUsed),
timestamp: utils.toBuffer(block.timestamp),
extraData: Buffer.from(block.extraData.replace('0x', ''), 'hex').slice(0, dataBuff.length - 65),
mixHash: Buffer.from(block.mixHash.replace('0x', ''), 'hex'),
nonce: Buffer.from(block.nonce.replace('0x', ''), 'hex')
}, [4])
const pub = utils.ecrecover(sigHash.hash(), signature.v, signature.r, signature.s)
const address = utils.pubToAddress(pub).toString('hex')
still no luck address is now 0x57aa03773cd7550e216b4f3f3c9dc928cd881558
Yes, we should use special rlphash function(the second one is correct). You code seems good to me, have no idea for the incorrect result.
Btw, should utils.ecrecover returns an error if recover is failed?
@rjl493456442
Finally found the mistake.
transactionTrie: Buffer.from(block.transactionsRoot.replace('0x', ''), 'hex'),
should be transactionsTrie: Buffer.from(block.transactionsRoot.replace('0x', ''), 'hex'),
So final implemenation with some code cleaning:
const Web3 = require('web3')
const utils = require('ethereumjs-util')
const BlockHeader = require('ethereumjs-block/header')
const web3 = new Web3(new Web3.providers.HttpProvider('...my node'))
const block = web3.eth.getBlock(2848394, true)
const dataBuff = utils.toBuffer(block.extraData)
const sig = utils.fromRpcSig(dataBuff.slice(dataBuff.length - 65, dataBuff.length))
block.extraData = '0x' + utils.toBuffer(block.extraData).slice(0, dataBuff.length - 65).toString('hex')
const headerHash = new BlockHeader({
parentHash: utils.toBuffer(block.parentHash),
uncleHash: utils.toBuffer(block.sha3Uncles),
coinbase: utils.toBuffer(block.miner),
stateRoot: utils.toBuffer(block.stateRoot),
transactionsTrie: utils.toBuffer(block.transactionsRoot),
receiptTrie: utils.toBuffer(block.receiptsRoot),
bloom: utils.toBuffer(block.logsBloom),
difficulty: utils.toBuffer(block.difficulty.toNumber()),
number: utils.toBuffer(block.number),
gasLimit: utils.toBuffer(block.gasLimit),
gasUsed: utils.toBuffer(block.gasUsed),
timestamp: utils.toBuffer(block.timestamp),
extraData: utils.toBuffer(block.extraData),
mixHash: utils.toBuffer(block.mixHash),
nonce: utils.toBuffer(block.nonce)
})
const pub = utils.ecrecover(headerHash.hash(), sig.v, sig.r, sig.s)
const address = utils.addHexPrefix(utils.pubToAddress(pub).toString('hex'))
console.log(headerHash.hash().toString('hex'))
console.log(address) // returns expected result
Thanks a lot for help!
Most helpful comment
@rjl493456442
Finally found the mistake.
transactionTrie: Buffer.from(block.transactionsRoot.replace('0x', ''), 'hex'),should be transactionsTrie: Buffer.from(block.transactionsRoot.replace('0x', ''), 'hex'),
So final implemenation with some code cleaning:
Thanks a lot for help!