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

以太坊矿工出块的完整过程

创建矿工

miner/worker.go

func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(*types.Block) bool, init bool) *worker {
 ...
worker.wg.Add(4)
    go worker.mainLoop()
    go worker.newWorkLoop(recommit)
    go worker.resultLoop()
    go worker.taskLoop()

接收任务

// newWorkLoop is a standalone goroutine to submit new mining work upon received events.
func (w *worker) newWorkLoop(recommit time.Duration) {
...
// commit aborts in-flight transaction execution with given signal and resubmits a new one.
    commit := func(noempty bool, s int32) {
        if interrupt != nil {
            atomic.StoreInt32(interrupt, s)
        }
        interrupt = new(int32)
        select {
        case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp}: //接收任务

任务传递

// mainLoop is a standalone goroutine to regenerate the sealing task based on the received event.
func (w *worker) mainLoop() {
....

    for {
        select {
        case req := <-w.newWorkCh:
            w.commitNewWork(req.interrupt, req.noempty, req.timestamp) // 提交任务

开始提交

// commitNewWork generates several new sealing tasks based on the parent block.
func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) {
    ...
    w.commit(uncles, w.fullTaskHook, true, tstart) // 开始提交

组装区块

func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error {
...
    block, receipts, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, txs, uncles, cpyReceipts) // 通过对应共识组装最后区块
    if err != nil {
        return err
    }
    if w.isRunning() {
        if interval != nil {
            interval()
        }
        select {
        case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: //开始广播区块
func (w *worker) taskLoop() {
     ...
        if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { // 开始矿工签名
                log.Warn("Block sealing failed", "err", err)
                w.pendingMu.Lock()
                delete(w.pendingTasks, sealHash)
                w.pendingMu.Unlock()
            }

矿工签名

func (c *Congress) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
// Sign all the things!
    sighash, err := signFn(accounts.Account{Address: val}, accounts.MimetypeCongress, CongressRLP(header))
    if err != nil {
        return err
    }
    copy(header.Extra[len(header.Extra)-extraSeal:], sighash) //将签名放到区块header.Extra字段

    // Wait until sealing is terminated or delay timeout.
    log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
    go func() {
        select {
        case <-stop:
            return
        case <-time.After(delay):
        }

        select {
        case results <- block.WithSeal(header): // 返回给上一步的 w.resultCh
        default:
            log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header))
        }
    }()

广播区块

func (w *worker) resultLoop() {
    defer w.wg.Done()
    for {
        select {
        case block := <-w.resultCh: // 接收到上步矿工签名的区块
        ...
        // Commit block and state to database.
        _, err := w.chain.WriteBlockWithState(block, receipts, logs, task.state, true) // 更新本地数据
        ...
        // Broadcast the block and announce chain insertion event
            w.mux.Post(core.NewMinedBlockEvent{Block: block}) // 广播区块

            // Insert the block into the set of pending ones to resultLoop for confirmations
            w.unconfirmed.Insert(block.NumberU64(), block.Hash())

以太坊部署合约时的地址是怎么计算的

先看代码 core/state_processor.go

func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, modOptions ...ModifyProcessOptionFunc) (*types.Receipt, error) {
...
    // If the transaction created a contract, store the creation address in the receipt.
    if msg.To() == nil {
        receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
    }

其中的evm.TxContext.Origin 为当前部署合约交易发起地址
core/evm.go

// NewEVMTxContext creates a new transaction context for a single transaction.
func NewEVMTxContext(msg Message) vm.TxContext {
    return vm.TxContext{
        Origin:   msg.From(),
        GasPrice: new(big.Int).Set(msg.GasPrice()),
    }
}

结论

合约地址ContractAddress通过部署合约发起地址和当前发起交易所在nonce计算所得

所以如果知道合约部署地址,就可以猜出对应的合约部署时地址了,可以用于一些提前抢单操作。。

以太坊的几种同步模式

查看geth命令行参数geth --help

--syncmode value                    Blockchain sync mode ("snap", "full" or "light") (default: snap)

参数支持"full", "snap", "light" 三种模式「原先的"fast"已被 "snap"替代」

查看官方文档

同步模式
--syncmode <mode> 您可以使用确定网络中节点类型的参数以三种不同同步模式之一启动 Geth 。

这些是:

  • Full : 下载所有区块(包括标题、交易和收据)并通过执行每个区块增量生成区块链的状态。
  • Snap(默认):与快速相同的功能,但具有更快的算法。
  • Light:下载所有区块头、区块数据,并随机验证一些。

官方推荐使用快照同步,简单说就是新的算法替代原先的fast模式,

请注意,快照同步已在 Geth v1.10.0 中提供,但尚未启用。
原因是提供快照同步需要节点已经生成快照加速结构,目前还没有,因为它也在 v1.10.0 中提供。
您可以通过 手动启用快照同步--syncmode snap,
但请注意,我们预计它要在柏林之后的几周内才能找到合适的对等方。
当我们觉得有足够的对等点可以依赖它时,我们将默认启用它。

此时已设置为默认模式

以太坊存档节点有什么用?

举个例子,如果你想知道4,000,000区块的以太坊账户余额,那么就需要运行存档节点,然后查询这个数字。这个节点依赖于一些专门的用例,但是对区块链的安全性和信任模型来说其实并没有影响。

内容引用

https://www.ccvalue.cn/article/2011.html

Transaction gasPrice (0) is too low for the next block, which has a baseFeePerGas of

问题描述

为了对比数据方便,排除发起交易gas消耗引起的账户余额差别,会将hardhat test 脚本中设置发起交易,设置gasPrice:0

await contract.withdraw({from: accounts[15], gasPrice: 0})

执行hardhat test时报以下错误

Transaction gasPrice (0) is too low for the next block, which has a baseFeePerGas of 8

解决方案

hardhat-config.js中设置initialBaseFeePerGas: 0

 networks: {
        hardhat: {
            ...
            initialBaseFeePerGas: 0
        }
    }

参考

https://github.com/nomiclabs/hardhat/issues/1216
https://github.com/nomiclabs/hardhat/blob/8e219bfc4112488953508eddd826d537bc71e803/docs/hardhat-network/reference/README.md