Go-ethereum: Miner info is empty in block

Created on 20 Aug 2018  路  7Comments  路  Source: ethereum/go-ethereum

Hi!

Trying to get information about blocks. For this I use web3 methods. All information displays normaly expect miner address. Tested in rinkeby network

System information

Geth version: 1.8.13
OS & Version: Linux

Expected behaviour

Miner address should be present in block information

Actual behaviour

Miner address in null 0x0000000000000000000000000000000000000000

Steps to reproduce the behaviour

  1. Run geth geth --rpc --rpcaddr 0.0.0.0 --rpcvhosts * --rinkeby --syncmode "fast"
  2. Try to get information about any block, e.g.
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

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:

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!

All 7 comments

@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:

  1. Can I use Block hash from eth_getBlock, or I should compute it like here https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L145
  2. I tried to create a block header hash like this:
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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

keitaj picture keitaj  路  3Comments

phpsamsb picture phpsamsb  路  3Comments

VenusHu picture VenusHu  路  3Comments

362228416 picture 362228416  路  3Comments

bgrieder picture bgrieder  路  3Comments