ethereum / go-ethereum

Go implementation of the Ethereum protocol
https://geth.ethereum.org
GNU Lesser General Public License v3.0
47.55k stars 20.13k forks source link

Clique: blocks are always mined by 0x0 #15651

Closed flynn1 closed 6 years ago

flynn1 commented 6 years ago

System information

Geth version: 1.7.3-stable OS & Version: Linux

Expected behaviour

Block should be mined by signer

Actual behaviour

Block is mined by 0x0

Steps to reproduce the behaviour

Notes

Above I described how I setup the testnet, there should be more signers but it's more clear with one. The command clique.getSnapshot() shows the block is correctly signed, but the miner is set to 0x0, ignoring miner.setEtherbase(). Am I missing something?

salanfe commented 6 years ago

same behavior for my clique dev net with 2 nodes. The blockchain is up and running but miner is always: 'miner': '0x0000000000000000000000000000000000000000'

shiqinfeng1 commented 6 years ago

‘miner’ field is used to indicate the candidate miner。or you can get signers by blockhash:

clique.getSignersAtHash('0x86837f148f096f1ce53463ecb4acf3d99bae0b2f0297dacbb6d33fcfdb7c04d9')
["0x5252781539b365e08015fa7ed77af5a36097f39d", "0x63f1de588c7ce855b66cf24b595a8991f921130d", "0xa1629411f4e8608a7bb88e8a7700f11c59175e72"]

or recover block miner from block.extraData.

facundomedica commented 6 years ago

I'm having the same issue. How is that https://www.rinkeby.io/#explorer gets the miner? @karalabe can you give us a clue on this?

facundomedica commented 6 years ago

Has someone solved this?

karalabe commented 6 years ago

The beneficiary field of the block header in the Clique protocol is used for a different purpose than in ethash.

In the PoW consensus engine, it's the miner. However in PoA, the signer is determined from a digital signature, which wouldn't fit into the beneficiary field (20 bytes vs. 65 byte signature), so in Clique, the beneficiary is used for voting on adding/removing signers. The signature for the block is contained within the block header's extradata field, and the address can be recovered from the signature.

https://github.com/ethereum/go-ethereum/issues/15651#issuecomment-369812845 already contains the answer on how you can get the signer address from a Clique block.

For more infos, please see the Clique consensus engine EIP https://github.com/ethereum/EIPs/issues/225.

facundomedica commented 6 years ago

@karalabe thanks!

EDIT:

In Go:

blk, err := conn.BlockByNumber(context.Background(), big.NewInt(2078))
pubkey, err := crypto.SigToPub(sigHash(blk.Header()).Bytes(), blk.Extra()[32:])
// log.Println(pubkey)
log.Println(err)
log.Println(crypto.PubkeyToAddress(*pubkey).Hex())

conn is ethclient.Client (returned by ethclient.Dial)

Swader commented 5 years ago

@facundomedica where does sigHash in the above snippet of yours come from?

facundomedica commented 5 years ago

@Swader as you can see I did comment that a long time ago but I was able to find that snippet on my machine, here you have sigHash:

func sigHash(header *types.Header) (hash common.Hash) {
    hasher := sha3.NewKeccak256()

    rlp.Encode(hasher, []interface{}{
        header.ParentHash,
        header.UncleHash,
        header.Coinbase,
        header.Root,
        header.TxHash,
        header.ReceiptHash,
        header.Bloom,
        header.Difficulty,
        header.Number,
        header.GasLimit,
        header.GasUsed,
        header.Time,
        header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
        header.MixDigest,
        header.Nonce,
    })
    hasher.Sum(hash[:0])
    return hash
}

I'm afraid I cannot answer any questions about this as I don't even remember what this was for. Hope it helped!

Swader commented 5 years ago

@facundomedica thank you, perfect! That solved it!

northeusunshine commented 5 years ago

@shiqinfeng1 : How can I use web3, or web3_extended to call clique.getSignersAtHash() function to get miner address? thanks

‘miner’ field is used to indicate the candidate miner。or you can get signers by blockhash:

clique.getSignersAtHash('0x86837f148f096f1ce53463ecb4acf3d99bae0b2f0297dacbb6d33fcfdb7c04d9')
["0x5252781539b365e08015fa7ed77af5a36097f39d", "0x63f1de588c7ce855b66cf24b595a8991f921130d", "0xa1629411f4e8608a7bb88e8a7700f11c59175e72"]

or recover block miner from block.extraData.

karalabe commented 5 years ago

Geth exposes the clique methods on the RPC. From this point onward it's up to you to call them with whatever library. The RPC method is clique_getSignersAtHash, I assume web3 or any other library should be able to make a low level query.

northeusunshine commented 5 years ago

When I send json RPC call using postman, it really works. But I call the mothed via web3, it says TypeError: web3.clique_getSignersAtHash is not a function. What's the correct way to call the method using web3 library? Thanks.

My call code lines are as below:

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://192.168.43.185:8545"));
//blockhash: 0x4122fc7595ded3760f5cd988927efa75a8df15ca955ebe740ba7ae70d4f160b8
web3.clique_getSignersAtHash('0x4122fc7595ded3760f5cd988927efa75a8df15ca955ebe740ba7ae70d4f160b8'); 
karalabe commented 5 years ago

You'll need to find a low level way to directly call a method. If it's not integrated into the JS api, you'll need to pass it by string to something. I'd recommend you open an issue/question on the web3.js repo (https://github.com/ethereum/web3.js/), I'm not familiar with that at all so can't really help beyond the above.

northeusunshine commented 5 years ago

I found a strange problem: To verify, I set up a private POA chain with 3 nodes, all of them are has a sealer account. I launch two nodes only, the blocks can be signed by the two nodes correctly. when I call clique.getSignersAtHash('block hash value') in attached geth console, the result also include the third signer, It's rather strange because the third node is not working. How can I get correct signer address of each block? Thanks. // I verified you suggestion, sending low level RPC call to node via web3, it works,thanks for you help. I share the code I use here for reference to who need: const Web3 = require('web3');

const web3 = new Web3('http://localhost:8545');
var async = require('asyncawait/async');
var await = require('asyncawait/await');
const main = async () => {
    test = await web3.currentProvider.send("clique_getSignersAtHash",['block hash value']);
    console.log(test);
};
main();
luchenqun commented 2 years ago
import { ethers } from "ethers";
const cliqueMiner = (block) => {
  try {
    const keys = ["parentHash", "sha3Uncles", "miner", "stateRoot", "transactionsRoot", "receiptsRoot", "logsBloom", "difficulty", "number", "gasLimit", "gasUsed", "timestamp", "extraData", "mixHash", "nonce", "baseFeePerGas"];
    const datas = [];
    for (const key of keys) {
      let data = block[key];
      if (key == "baseFeePerGas" && !data) {
        continue;
      }
      if (key == "extraData") {
        data = data.substr(0, 66);
      } else if (key == "difficulty") {
        data = parseInt(data);
      }

      if (typeof data == "number") {
        data = ethers.BigNumber.from(data).toHexString();
      }
      if (data.length % 2 == 1) {
        data = "0x0" + data.substr(2); // RLP object must be BytesLike
      }
      datas.push(data);
    }
    console.log(datas);
    const digest = ethers.utils.keccak256(ethers.utils.RLP.encode(datas));
    const signature = "0x" + block["extraData"].substr(66);
    const miner = ethers.utils.recoverAddress(digest, signature);
    return miner;
  } catch (error) {
    console.log("error", error);
    return block.miner;
  }
};

// eth_getBlockByNumber
const block = {
  difficulty: "0x2",
  extraData: "0xd883010a0f846765746888676f312e31372e35856c696e757800000000000000cc6274ad7527edc1fc104ad149c3c3340a559e4197bfb5cdc69add1cd5e3a1fc3b3511ef2f474527731fb6502b72e3d36766f775a3f4b98bba1b29ae4f0aa76200",
  gasLimit: "0x47a57228001",
  gasUsed: "0x5208",
  hash: "0xdf4d0f6ec0403cb12063cf0c865ff32d2e006e44673ed3933cf1d3aae98e31bb",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x0000000000000000000000000000000000000000",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000000",
  number: "0x1",
  parentHash: "0xda1977f3cfeddfde314652d125c3a8c7a8331e664dace0e4b76319abcc720eb1",
  receiptsRoot: "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: "0x2d5",
  stateRoot: "0x7d5885026291a063b55f5213697fd54c1b64efbfca8f6ff12ff31a1619a3a4b5",
  timestamp: "0x6230b2ea",
  totalDifficulty: "0x3",
  transactions: ["0xa750ddae2ec3bb96125794d7446e941abef3c508ba8ca62b5569d34876fa18ea"],
  transactionsRoot: "0x8b077b57dc9364facbee380526f640ad8161c5104cbd190ebae212020fd415d4",
  uncles: [],
};

console.log(cliqueMiner(block)); // 0x1111102Dd32160B064F2A512CDEf74bFdB6a9F96
ghost commented 2 years ago

@luchenqun More accrate one using ethers and axios

const ethers = require('ethers');
const axios = require('axios');

function decimalToHexString(number) {
  if (number < 0) {
    number = 0xFFFFFFFF + number + 1;
  }

  return `0x${number.toString(16)}`;
}

const cliqueMiner = (block) => {
  try {
    const keys = ["parentHash", "sha3Uncles", "miner", "stateRoot", "transactionsRoot", "receiptsRoot", "logsBloom", "difficulty", "number", "gasLimit", "gasUsed", "timestamp", "extraData", "mixHash", "nonce", "baseFeePerGas"];
    const datas = [];
    for (const key of keys) {
      let data = block[key];
      if (!data) {
        continue;
      }
      if (key === 'extraData') {
        data = data.substr(0, 66);
      } else if (key === 'difficulty' || key === 'baseFeePerGas') {
        data = parseInt(data);
      }

      if (typeof data === 'number') {
        data = ethers.BigNumber.from(data).toHexString();
      }
      if (data.length % 2 == 1) {
        data = "0x0" + data.substr(2); // RLP object must be BytesLike
      }
      datas.push(data);
    }
    console.log(datas);
    const digest = ethers.utils.keccak256(ethers.utils.RLP.encode(datas));
    const signature = "0x" + block["extraData"].substr(66);
    const miner = ethers.utils.recoverAddress(digest, signature);
    return miner;
  } catch (error) {
    console.log("error", error);
    return block.miner;
  }
};

const getBlockMiner = async (blockNumber) => {
  try {
    const params = {
      jsonrpc: '2.0',
      id: 1,
      method: 'eth_getBlockByNumber',
      params: [ decimalToHexString(blockNumber), false ]
    }
    const { data } = await axios.post('https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161', params);
    console.log(data?.result)
    const miner = cliqueMiner(data?.result);
    console.log(`${parseInt(data?.result?.number)} mined by ${miner}`);
  } catch (e) {
    console.error(e);
  }
}

getBlockMiner(5893851);
{
  baseFeePerGas: '0x7',
  difficulty: '0x1',
  extraData: '0x726f6e696e6b61697a656e2e6574682d76616c696461746f7200000000000000075e0a80e74ffe303c10b248bd1f54b18ac1e75ae6b1b7859d26eaccd69a9ff330bb1759747e0fcbf89aed4e2b431ce8ae87ecdb27472ce4103a1ef7fe359ae801',
  gasLimit: '0x1c95111',
  gasUsed: '0x23fdcd',
  hash: '0x2332429886ea8e7445bbcfcc2a8f19dc4327805a2df8ce0a4ad11f3655383411',
  logsBloom: '0x0802000000002000000001000000080000002082000008100000020000104000000080028000800088000013004100000000000050048000408002c001241200102111040400000001200008000088800200800000048800001000000000200000000000020000000100080008000884000000300000000500000010800840004800004600000080000202080011801000100800003400000000a00000010010020000020020001000200890081000002100890010000404800000080008100000004202001400100400000000000a00010008000200000010200000008860000018340000000004004008808000080000002200000100000800210804620000',
  miner: '0x0000000000000000000000000000000000000000',
  mixHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  nonce: '0x0000000000000000',
  number: '0x59eedb',
  parentHash: '0x31d2aa920425f07531ad1faa7c748e636bcb6300f6c151ae1339cc8c3c57624c',
  receiptsRoot: '0x9051df9f381255dd02befc98702b496fe6f3bafdff062563acced6a3fd7e4f40',
  sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
  size: '0x2bf5',
  stateRoot: '0xd88004cedf8660498c4184adac905e0755cefc5945f8b903467788d32a6ab0e1',
  timestamp: '0x619b8a09',
  totalDifficulty: '0x83c20e',
  transactions: [
    '0x517b815f786de0a652b9f50058e1557bf34539e878b83215351def9719152e28',
    '0x41cedc3ba5883a6c2c76dbf9b32154faa4042605673607380fc91ceee429e2e7',
    '0x537140d56a15f753f6797c76584f7ca8be30faad64aa14181d8083b72ef632bb',
    '0x530c32a8c547e282e815fd58db242244908f8e03565f662d8d2891e8206f57c7',
    '0x2b3deea73c2b7def79a7e5192403892fa97ee719a46024e7b931ff316245fda9',
    '0xf75d17b2fd5944a1f5aca4f6fa077ffa9051e92b4832dad8e821c50cd2085e0c',
    '0xfd28806227c5c9452beb5919b99e59d9c0d97f7ac05e06844d3e9355915ad726',
    '0x78d5f826a565cf71ef4082e94b7248230391dd417cb648587806dcf5d1ff43f6',
    '0x37f8d62c83bd5cab81eccd04b32a3989a38a020e21fbe0f035535dad60005ca5',
    '0x173f2da139000dea3fdd9f826d3b60deb7a92213fde3b8f296018f8663c5d483',
    '0xb62ae787bb4c13dc7f43930724b7bf1c489ee195521e1a92b45758254ef518c3',
    '0x4e0b72fd1dc3c6de27c5c3c355c83d579ff8d4007a1c6060d0cda7d4eec24df5',
    '0x96bf1ccf377b6053a7a456ccd9e13c52484bbc30d3588358ee43b22fb99a2706',
    '0xb087d17381124580e306312009f7bd62039c174bca545e74b65f2c40c1e376ae',
    '0x2528858591ddeb2b06310995a6e4bc8beed203dcda0eaf62f203ffa55b868106',
    '0x101253529bcaffbdfc1aa456c33be2f9835230ca1b891cf705c757d5f2fd05f6',
    '0x37b1af969b419f14221ff6ede0ee400fa96a9c95c8cacea123d55952ca7db2c5',
    '0x26738428ea65b56339d0b35c994e735993bf38eed16a0c9b71fa7258656ef5ca',
    '0x1f39c101e5176315ef910e9180191de93456d6035ef3283769298b9a7c1de13d',
    '0x3d2ff01a7d8f5c626403dce4eae41054da58af27ee097f61b6c86d8a12462950',
    '0x3484db37aff742c12a5605445ef948d8271f24ae11e6328cc1f77cb639d12361',
    '0x600084ad298f13841baf6960b483f6927349f758aa8d922fe2f073e6f77df7a0',
    '0x337fbe5b9352a96d360d78a2917efb657c17ac538650c01a80b0f6b8a40b4071',
    '0xb9fc14a97fbd2df9c43846b54e349de6b5060b61c1b46c466212123145281172',
    '0x677703ee5705108f45e9eb2bf474fe7d60301f10e89315929d4bcb3c06eab88f',
    '0x5cae27b66c54ff7c824d80771c962e1723e5280e45cb42dfcbd637cec5a497da',
    '0xaed37c57d7350516c18e41f2adc896eb34bc99340c6ae7b1dd9a42347eed73c2',
    '0x0fd1b81913584f7fd2717b52d98df260256cd4a8ca4211bdc132fe5a9e3ca51e',
    '0x028cd81f47ce7949397c96236e8174837e5ab9fa9c828dffbc6cc68a075c8185'
  ],
  transactionsRoot: '0x5051c5f369fda4558ec05795c446822eb932f0396aaa6ce3f30c3459417f7789',
  uncles: []
}
[
  '0x31d2aa920425f07531ad1faa7c748e636bcb6300f6c151ae1339cc8c3c57624c',
  '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
  '0x0000000000000000000000000000000000000000',
  '0xd88004cedf8660498c4184adac905e0755cefc5945f8b903467788d32a6ab0e1',
  '0x5051c5f369fda4558ec05795c446822eb932f0396aaa6ce3f30c3459417f7789',
  '0x9051df9f381255dd02befc98702b496fe6f3bafdff062563acced6a3fd7e4f40',
  '0x0802000000002000000001000000080000002082000008100000020000104000000080028000800088000013004100000000000050048000408002c001241200102111040400000001200008000088800200800000048800001000000000200000000000020000000100080008000884000000300000000500000010800840004800004600000080000202080011801000100800003400000000a00000010010020000020020001000200890081000002100890010000404800000080008100000004202001400100400000000000a00010008000200000010200000008860000018340000000004004008808000080000002200000100000800210804620000',
  '0x01',
  '0x59eedb',
  '0x01c95111',
  '0x23fdcd',
  '0x619b8a09',
  '0x726f6e696e6b61697a656e2e6574682d76616c696461746f7200000000000000',
  '0x0000000000000000000000000000000000000000000000000000000000000000',
  '0x0000000000000000',
  '0x07'
]
5893851 mined by 0x9d525E28Fe5830eE92d7Aa799c4D21590567B595
anhnhgutech commented 6 months ago

@luchenqun Hi, in your recover miner logic, what happens when the block is epoch block?