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 }