github.com/dim4egster/coreth@v0.10.2/plugin/evm/syncervm_server.go (about)

     1  // (c) 2021-2022, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package evm
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/dim4egster/qmallgo/database"
    10  	"github.com/dim4egster/qmallgo/snow/engine/snowman/block"
    11  
    12  	"github.com/dim4egster/coreth/core"
    13  	"github.com/dim4egster/coreth/plugin/evm/message"
    14  	"github.com/ethereum/go-ethereum/common"
    15  	"github.com/ethereum/go-ethereum/log"
    16  )
    17  
    18  type stateSyncServerConfig struct {
    19  	Chain      *core.BlockChain
    20  	AtomicTrie AtomicTrie
    21  
    22  	// SyncableInterval is the interval at which blocks are eligible to provide syncable block summaries.
    23  	SyncableInterval uint64
    24  }
    25  
    26  type stateSyncServer struct {
    27  	chain      *core.BlockChain
    28  	atomicTrie AtomicTrie
    29  
    30  	syncableInterval uint64
    31  }
    32  
    33  type StateSyncServer interface {
    34  	GetLastStateSummary() (block.StateSummary, error)
    35  	GetStateSummary(uint64) (block.StateSummary, error)
    36  }
    37  
    38  func NewStateSyncServer(config *stateSyncServerConfig) StateSyncServer {
    39  	return &stateSyncServer{
    40  		chain:            config.Chain,
    41  		atomicTrie:       config.AtomicTrie,
    42  		syncableInterval: config.SyncableInterval,
    43  	}
    44  }
    45  
    46  // stateSummaryAtHeight returns the SyncSummary at [height] if valid and available.
    47  func (server *stateSyncServer) stateSummaryAtHeight(height uint64) (message.SyncSummary, error) {
    48  	atomicRoot, err := server.atomicTrie.Root(height)
    49  	if err != nil {
    50  		return message.SyncSummary{}, fmt.Errorf("error getting atomic trie root for height (%d): %w", height, err)
    51  	}
    52  
    53  	if (atomicRoot == common.Hash{}) {
    54  		return message.SyncSummary{}, fmt.Errorf("atomic trie root not found for height (%d)", height)
    55  	}
    56  
    57  	blk := server.chain.GetBlockByNumber(height)
    58  	if blk == nil {
    59  		return message.SyncSummary{}, fmt.Errorf("block not found for height (%d)", height)
    60  	}
    61  
    62  	if !server.chain.HasState(blk.Root()) {
    63  		return message.SyncSummary{}, fmt.Errorf("block root does not exist for height (%d), root (%s)", height, blk.Root())
    64  	}
    65  
    66  	summary, err := message.NewSyncSummary(blk.Hash(), height, blk.Root(), atomicRoot)
    67  	if err != nil {
    68  		return message.SyncSummary{}, fmt.Errorf("failed to construct syncable block at height %d: %w", height, err)
    69  	}
    70  	return summary, nil
    71  }
    72  
    73  // GetLastStateSummary returns the latest state summary.
    74  // State summary is calculated by the block nearest to last accepted
    75  // that is divisible by [syncableInterval]
    76  // If no summary is available, [database.ErrNotFound] must be returned.
    77  func (server *stateSyncServer) GetLastStateSummary() (block.StateSummary, error) {
    78  	lastHeight := server.chain.LastAcceptedBlock().NumberU64()
    79  	lastSyncSummaryNumber := lastHeight - lastHeight%server.syncableInterval
    80  
    81  	summary, err := server.stateSummaryAtHeight(lastSyncSummaryNumber)
    82  	if err != nil {
    83  		log.Debug("could not get latest state summary", "err", err)
    84  		return nil, database.ErrNotFound
    85  	}
    86  	log.Debug("Serving syncable block at latest height", "summary", summary)
    87  	return summary, nil
    88  }
    89  
    90  // GetStateSummary implements StateSyncableVM and returns a summary corresponding
    91  // to the provided [height] if the node can serve state sync data for that key.
    92  // If not, [database.ErrNotFound] must be returned.
    93  func (server *stateSyncServer) GetStateSummary(height uint64) (block.StateSummary, error) {
    94  	summaryBlock := server.chain.GetBlockByNumber(height)
    95  	if summaryBlock == nil ||
    96  		summaryBlock.NumberU64() > server.chain.LastAcceptedBlock().NumberU64() ||
    97  		summaryBlock.NumberU64()%server.syncableInterval != 0 {
    98  		return nil, database.ErrNotFound
    99  	}
   100  
   101  	summary, err := server.stateSummaryAtHeight(summaryBlock.NumberU64())
   102  	if err != nil {
   103  		log.Debug("could not get state summary", "height", height, "err", err)
   104  		return nil, database.ErrNotFound
   105  	}
   106  
   107  	log.Debug("Serving syncable block at requested height", "height", height, "summary", summary)
   108  	return summary, nil
   109  }