您正在查看: Ethereum-新手教程 分类下的文章

如何查看infura是否稳定

背景

一些服务为了稳定和省去自己维护同步节点,常会使用infura 类似的三方节点服务,但有时服务报访问不稳定,需要排查下infura官方服务是否有异常

查看对应类型网关,一段时间内是否有异常

https://status.infura.io/

查看对外通知

https://status.infura.io/history

解决方式

使用多个三方RPC提供方,通过类似 eRPC服务实现高容错

检查签名对于给定的签名者和数据哈希是否有效

github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/659f3063f82422cef820de746444e6f6cba6ca7c/contracts/utils/cryptography/SignatureChecker.sol

/**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC-1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
        if (signer.code.length == 0) {
            (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature);
            return err == ECDSA.RecoverError.NoError && recovered == signer;
        } else {
            return isValidERC1271SignatureNow(signer, hash, signature);
        }
    }

测试例子

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

contract TestSignatureChecker {
    function verify(address _signer, bytes32 messageHash,  bytes memory _signature) external view returns(bool) {
        return SignatureChecker.isValidSignatureNow(_signer, messageHash, _signature);
    }
}

Geth Clique共识下miner显示0x地址

问题

在Clique共识下,查看block

eth.getBlockByNumber(1000);

返回数据中miner为0x地址

miner: "0x0000000000000000000000000000000000000000",

解决

对于Clique共识查看某个区块的miner,通过getSignersAtHash查看

clique.getSignersAtHash("0xec6058d9364569e92a7e7c19889fa4daf86111ddf29dfcd6993be697b1cdd553")
["0x0eb7365be3c1fa53fe6ad8080c723def2a4cbb9f", "0x45d959f955e6ba85c03d1131e8e6efbf7061b6ec", "0x48f58ba03e2bfe0f84813184ba605c530ce333d5", "0x57fa14bde7440f47f3a9ddc854c1281d1b7a2fc5", "0x5cd8f88f97ead6f84957cf5a2c80db33da53a8c7"]

对于blockscout浏览器显示0x问题,需要首次启动前,修改docker-compose/envs/common-blockscout.env

BLOCK_TRANSFORMER=clique

引用

https://github.com/blockscout/blockscout/issues/1990
https://github.com/ethereum/go-ethereum/issues/15651

forkchoiceUpdatedV3 must only be called for cancun payloads

启动eth2.0 一段时间后,报如下错误

WARN [05-24|11:39:02.090] Served engine_forkchoiceUpdatedV3        conn=127.0.0.1:53124 reqid=355251 duration="74.273µs" err="Unsupported fork" errdata="{Error:forkchoiceUpdatedV3 must only be called for cancun payloads}"

查看代码
https://github.com/ethereum/go-ethereum/blob/b6474e9f90c88003de7d7eb993ddb5f60133172e/eth/catalyst/api.go#L213-L224

// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root
// in the payload attributes. It supports only PayloadAttributesV3.
func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
    if params != nil {
        if params.Withdrawals == nil {
            return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals"))
        }
        if params.BeaconRoot == nil {
            return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root"))
        }
        if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { // 关键代码
            return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads"))
        }
    }

跟踪下代码,
https://github.com/ethereum/go-ethereum/blob/b6474e9f90c88003de7d7eb993ddb5f60133172e/params/config.go#L763-L778

// LatestFork returns the latest time-based fork that would be active for the given time.
func (c *ChainConfig) LatestFork(time uint64) forks.Fork {
    // Assume last non-time-based fork has passed.
    london := c.LondonBlock

    switch {
    case c.IsPrague(london, time):
        return forks.Prague
    case c.IsCancun(london, time):
        return forks.Cancun
    case c.IsShanghai(london, time):
        return forks.Shanghai
    default:
        return forks.Paris
    }
}

当前genesis配置如下

{
  "config": {
    "chainId": ....,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0,
    "londonBlock": 0,
    "mergeNetsplitBlock": 0,
    "terminalTotalDifficulty": 0,
    "terminalTotalDifficultyPassed": true,
    "shanghaiTime": 0,
    "cancunTime": 0,
    "pragueTime": 1716532255
  },
  ....
  "coinbase": "0x0000000000000000000000000000000000000000",
  "difficulty": "0x01",
  "extraData": "",
  "gasLimit": "0x17d7840",
  "nonce": "0x1234",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp": "1715760655"

由于设置了pragueTime,所以LatestFork会返回Prague fork,不会是Cancun,所以ForkchoiceUpdatedV3会报错,至于Prague为什么不支持ForkchoiceUpdatedV3,留个TODO

目前要做的是把最新的fork改为Cancun

  1. 将genesis.json中的pragueTime删掉
  2. 停止geth服务
  3. 重新初始化
    ./geth --config ./config/config.toml init ./config/genesis.json
  4. 重启geth服务