github.com/jimmyx0x/go-ethereum@v1.10.28/consensus/merger.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package consensus
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  
    23  	"github.com/ethereum/go-ethereum/core/rawdb"
    24  	"github.com/ethereum/go-ethereum/ethdb"
    25  	"github.com/ethereum/go-ethereum/log"
    26  	"github.com/ethereum/go-ethereum/rlp"
    27  )
    28  
    29  // transitionStatus describes the status of eth1/2 transition. This switch
    30  // between modes is a one-way action which is triggered by corresponding
    31  // consensus-layer message.
    32  type transitionStatus struct {
    33  	LeftPoW    bool // The flag is set when the first NewHead message received
    34  	EnteredPoS bool // The flag is set when the first FinalisedBlock message received
    35  }
    36  
    37  // Merger is an internal help structure used to track the eth1/2 transition status.
    38  // It's a common structure can be used in both full node and light client.
    39  type Merger struct {
    40  	db     ethdb.KeyValueStore
    41  	status transitionStatus
    42  	mu     sync.RWMutex
    43  }
    44  
    45  // NewMerger creates a new Merger which stores its transition status in the provided db.
    46  func NewMerger(db ethdb.KeyValueStore) *Merger {
    47  	var status transitionStatus
    48  	blob := rawdb.ReadTransitionStatus(db)
    49  	if len(blob) != 0 {
    50  		if err := rlp.DecodeBytes(blob, &status); err != nil {
    51  			log.Crit("Failed to decode the transition status", "err", err)
    52  		}
    53  	}
    54  	return &Merger{
    55  		db:     db,
    56  		status: status,
    57  	}
    58  }
    59  
    60  // ReachTTD is called whenever the first NewHead message received
    61  // from the consensus-layer.
    62  func (m *Merger) ReachTTD() {
    63  	m.mu.Lock()
    64  	defer m.mu.Unlock()
    65  
    66  	if m.status.LeftPoW {
    67  		return
    68  	}
    69  	m.status = transitionStatus{LeftPoW: true}
    70  	blob, err := rlp.EncodeToBytes(m.status)
    71  	if err != nil {
    72  		panic(fmt.Sprintf("Failed to encode the transition status: %v", err))
    73  	}
    74  	rawdb.WriteTransitionStatus(m.db, blob)
    75  	log.Info("Left PoW stage")
    76  }
    77  
    78  // FinalizePoS is called whenever the first FinalisedBlock message received
    79  // from the consensus-layer.
    80  func (m *Merger) FinalizePoS() {
    81  	m.mu.Lock()
    82  	defer m.mu.Unlock()
    83  
    84  	if m.status.EnteredPoS {
    85  		return
    86  	}
    87  	m.status = transitionStatus{LeftPoW: true, EnteredPoS: true}
    88  	blob, err := rlp.EncodeToBytes(m.status)
    89  	if err != nil {
    90  		panic(fmt.Sprintf("Failed to encode the transition status: %v", err))
    91  	}
    92  	rawdb.WriteTransitionStatus(m.db, blob)
    93  	log.Info("Entered PoS stage")
    94  }
    95  
    96  // TDDReached reports whether the chain has left the PoW stage.
    97  func (m *Merger) TDDReached() bool {
    98  	m.mu.RLock()
    99  	defer m.mu.RUnlock()
   100  
   101  	return m.status.LeftPoW
   102  }
   103  
   104  // PoSFinalized reports whether the chain has entered the PoS stage.
   105  func (m *Merger) PoSFinalized() bool {
   106  	m.mu.RLock()
   107  	defer m.mu.RUnlock()
   108  
   109  	return m.status.EnteredPoS
   110  }