Closed flynn1 closed 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'
‘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.
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?
Has someone solved this?
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.
@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
)
@facundomedica where does sigHash
in the above snippet of yours come from?
@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!
@facundomedica thank you, perfect! That solved it!
@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.
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.
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');
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.
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();
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
@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
@luchenqun Hi, in your recover miner logic, what happens when the block is epoch block?
System information
Geth version:
1.7.3-stable
OS & Version: LinuxExpected behaviour
Block should be mined by signer
Actual behaviour
Block is mined by 0x0
Steps to reproduce the behaviour
geth account new
puppeth
(PoA, previously generated account as signer)geth init genesis.json
geth attach
personal.unlockAccount(eth.coinbase, 'pwd', 0)
miner.setEtherbase(eth.coinbase)
miner.start()
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, ignoringminer.setEtherbase()
. Am I missing something?