github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/avalanche/state/state.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package state 5 6 import ( 7 "go.uber.org/zap" 8 9 "github.com/MetalBlockchain/metalgo/cache" 10 "github.com/MetalBlockchain/metalgo/database" 11 "github.com/MetalBlockchain/metalgo/ids" 12 "github.com/MetalBlockchain/metalgo/snow/choices" 13 "github.com/MetalBlockchain/metalgo/snow/engine/avalanche/vertex" 14 "github.com/MetalBlockchain/metalgo/utils/logging" 15 "github.com/MetalBlockchain/metalgo/utils/wrappers" 16 ) 17 18 type state struct { 19 serializer *Serializer 20 log logging.Logger 21 22 dbCache cache.Cacher[ids.ID, any] 23 db database.Database 24 } 25 26 // Vertex retrieves the vertex with the given id from cache/disk. 27 // Returns nil if it's not found. 28 // TODO this should return an error 29 func (s *state) Vertex(id ids.ID) vertex.StatelessVertex { 30 if vtxIntf, found := s.dbCache.Get(id); found { 31 vtx, _ := vtxIntf.(vertex.StatelessVertex) 32 return vtx 33 } 34 35 bytes, err := s.db.Get(id[:]) 36 if err != nil { 37 s.log.Verbo("failed to get vertex from database", 38 zap.Binary("key", id[:]), 39 zap.Error(err), 40 ) 41 s.dbCache.Put(id, nil) 42 return nil 43 } 44 45 vtx, err := s.serializer.parseVertex(bytes) 46 if err != nil { 47 s.log.Error("failed parsing saved vertex", 48 zap.Binary("key", id[:]), 49 zap.Binary("vertex", bytes), 50 zap.Error(err), 51 ) 52 s.dbCache.Put(id, nil) 53 return nil 54 } 55 56 s.dbCache.Put(id, vtx) 57 return vtx 58 } 59 60 // SetVertex persists the vertex to the database and returns an error if it 61 // fails to write to the db 62 func (s *state) SetVertex(id ids.ID, vtx vertex.StatelessVertex) error { 63 s.dbCache.Put(id, vtx) 64 65 if vtx == nil { 66 return s.db.Delete(id[:]) 67 } 68 69 return s.db.Put(id[:], vtx.Bytes()) 70 } 71 72 func (s *state) Status(id ids.ID) choices.Status { 73 if statusIntf, found := s.dbCache.Get(id); found { 74 status, _ := statusIntf.(choices.Status) 75 return status 76 } 77 78 if val, err := database.GetUInt32(s.db, id[:]); err == nil { 79 // The key was in the database 80 status := choices.Status(val) 81 s.dbCache.Put(id, status) 82 return status 83 } 84 85 s.dbCache.Put(id, choices.Unknown) 86 return choices.Unknown 87 } 88 89 // SetStatus sets the status of the vertex and returns an error if it fails to write to the db 90 func (s *state) SetStatus(id ids.ID, status choices.Status) error { 91 s.dbCache.Put(id, status) 92 93 if status == choices.Unknown { 94 return s.db.Delete(id[:]) 95 } 96 return database.PutUInt32(s.db, id[:], uint32(status)) 97 } 98 99 func (s *state) Edge(id ids.ID) []ids.ID { 100 if frontierIntf, found := s.dbCache.Get(id); found { 101 frontier, _ := frontierIntf.([]ids.ID) 102 return frontier 103 } 104 105 if b, err := s.db.Get(id[:]); err == nil { 106 p := wrappers.Packer{Bytes: b} 107 108 frontierSize := p.UnpackInt() 109 frontier := make([]ids.ID, frontierSize) 110 for i := 0; i < int(frontierSize) && !p.Errored(); i++ { 111 id, err := ids.ToID(p.UnpackFixedBytes(ids.IDLen)) 112 p.Add(err) 113 frontier[i] = id 114 } 115 116 if p.Offset == len(b) && !p.Errored() { 117 s.dbCache.Put(id, frontier) 118 return frontier 119 } 120 s.log.Error("failed parsing saved edge", 121 zap.Binary("key", id[:]), 122 zap.Binary("edge", b), 123 zap.Error(err), 124 ) 125 } 126 127 s.dbCache.Put(id, nil) // Cache the miss 128 return nil 129 } 130 131 // SetEdge sets the frontier and returns an error if it fails to write to the db 132 func (s *state) SetEdge(id ids.ID, frontier []ids.ID) error { 133 s.dbCache.Put(id, frontier) 134 135 if len(frontier) == 0 { 136 return s.db.Delete(id[:]) 137 } 138 139 size := wrappers.IntLen + ids.IDLen*len(frontier) 140 p := wrappers.Packer{Bytes: make([]byte, size)} 141 p.PackInt(uint32(len(frontier))) 142 for _, id := range frontier { 143 p.PackFixedBytes(id[:]) 144 } 145 146 return s.db.Put(id[:], p.Bytes) 147 }