github.com/ethersphere/bee/v2@v2.2.0/pkg/statestore/storeadapter/storeadapter.go (about) 1 // Copyright 2023 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package storeadapter 6 7 import ( 8 "encoding" 9 "encoding/json" 10 "fmt" 11 "strings" 12 13 "github.com/ethersphere/bee/v2/pkg/storage" 14 "github.com/ethersphere/bee/v2/pkg/storage/migration" 15 "github.com/ethersphere/bee/v2/pkg/storage/storageutil" 16 ) 17 18 // stateStoreNamespace is the namespace used for state storage. 19 const stateStoreNamespace = "ss" 20 21 var _ storage.Item = (*proxyItem)(nil) 22 23 // proxyItem is a proxy object that implements the Item interface. 24 // It is an intermediary object between StateStorer and Store interfaces calls. 25 type proxyItem struct { 26 ns string 27 key string 28 obj interface{} 29 } 30 31 // ID implements Item interface. 32 func (pi *proxyItem) ID() string { 33 return pi.key 34 } 35 36 // Namespace implements Item interface. 37 func (pi *proxyItem) Namespace() string { 38 return pi.ns 39 } 40 41 // Marshal implements Item interface. 42 func (pi *proxyItem) Marshal() ([]byte, error) { 43 if pi == nil || pi.obj == nil { 44 return nil, nil 45 } 46 47 switch m := pi.obj.(type) { 48 case encoding.BinaryMarshaler: 49 return m.MarshalBinary() 50 case storage.Marshaler: 51 return m.Marshal() 52 } 53 return json.Marshal(pi.obj) 54 } 55 56 // Unmarshal implements Item interface. 57 func (pi *proxyItem) Unmarshal(data []byte) error { 58 if pi == nil || pi.obj == nil { 59 return nil 60 } 61 62 switch m := pi.obj.(type) { 63 case encoding.BinaryUnmarshaler: 64 return m.UnmarshalBinary(data) 65 case storage.Unmarshaler: 66 return m.Unmarshal(data) 67 } 68 return json.Unmarshal(data, &pi.obj) 69 } 70 71 // Clone implements Item interface. 72 func (pi *proxyItem) Clone() storage.Item { 73 if pi == nil { 74 return nil 75 } 76 77 obj := pi.obj 78 if cloner, ok := pi.obj.(storage.Cloner); ok { 79 obj = cloner.Clone() 80 } 81 return &proxyItem{ 82 ns: pi.ns, 83 key: pi.key, 84 obj: obj, 85 } 86 } 87 88 // String implements Item interface. 89 func (pi proxyItem) String() string { 90 return storageutil.JoinFields(pi.Namespace(), pi.ID()) 91 } 92 93 // newProxyItem creates a new proxyItem. 94 func newProxyItem(key string, obj interface{}) *proxyItem { 95 return &proxyItem{ns: stateStoreNamespace, key: key, obj: obj} 96 } 97 98 var _ storage.Item = (*rawItem)(nil) 99 100 // rawItem is a proxy object that implements the Item interface. 101 // It is an intermediary object between StateStorer and Store iterator calls. 102 type rawItem struct { 103 *proxyItem 104 } 105 106 // Marshal implements Item interface. 107 func (ri *rawItem) Marshal() ([]byte, error) { 108 if ri == nil || ri.proxyItem == nil || ri.proxyItem.obj == nil { 109 return nil, nil 110 } 111 112 if buf, ok := ri.proxyItem.obj.([]byte); ok { 113 return buf, nil 114 } 115 116 return ri.proxyItem.Marshal() 117 } 118 119 // Unmarshal implements Item interface. 120 func (ri *rawItem) Unmarshal(data []byte) error { 121 if ri == nil || ri.proxyItem == nil || ri.proxyItem.obj == nil || len(data) == 0 { 122 return nil 123 } 124 125 if buf, ok := ri.proxyItem.obj.([]byte); ok { 126 ri.proxyItem.obj = append(buf[:0], data...) 127 return nil 128 } 129 130 return ri.proxyItem.Unmarshal(data) 131 } 132 133 var ( 134 _ storage.StateStorer = (*StateStorerAdapter)(nil) 135 _ storage.StateStorerCleaner = (*StateStorerAdapter)(nil) 136 ) 137 138 // StateStorerAdapter is an adapter from Store to the StateStorer. 139 type StateStorerAdapter struct { 140 storage storage.Store 141 } 142 143 // Close implements StateStorer interface. 144 func (s *StateStorerAdapter) Close() error { 145 return s.storage.Close() 146 } 147 148 // Get implements StateStorer interface. 149 func (s *StateStorerAdapter) Get(key string, obj interface{}) (err error) { 150 return s.storage.Get(newProxyItem(key, obj)) 151 } 152 153 // Put implements StateStorer interface. 154 func (s *StateStorerAdapter) Put(key string, obj interface{}) (err error) { 155 return s.storage.Put(newProxyItem(key, obj)) 156 } 157 158 // Delete implements StateStorer interface. 159 func (s *StateStorerAdapter) Delete(key string) (err error) { 160 return s.storage.Delete(newProxyItem(key, nil)) 161 } 162 163 // Iterate implements StateStorer interface. 164 func (s *StateStorerAdapter) Iterate(prefix string, iterFunc storage.StateIterFunc) (err error) { 165 return s.storage.Iterate( 166 storage.Query{ 167 Factory: func() storage.Item { return &rawItem{newProxyItem("", []byte(nil))} }, 168 Prefix: prefix, 169 }, 170 func(res storage.Result) (stop bool, err error) { 171 key := []byte(prefix + res.ID) 172 val, err := res.Entry.(*rawItem).Marshal() 173 if err != nil { 174 return false, err 175 } 176 return iterFunc(key, val) 177 }, 178 ) 179 } 180 181 func (s *StateStorerAdapter) Nuke() error { 182 var ( 183 prefixesToPreserve = []string{ 184 "non-mineable-overlay", 185 "overlayV2_nonce", 186 "pseudosettle", 187 "accounting", 188 "swap", 189 } 190 keys []string 191 err error 192 ) 193 194 keys, err = s.collectKeysExcept(prefixesToPreserve) 195 if err != nil { 196 return fmt.Errorf("collect keys except: %w", err) 197 } 198 return s.deleteKeys(keys) 199 } 200 201 func (s *StateStorerAdapter) ClearForHopping() error { 202 var ( 203 prefixesToPreserve = []string{ 204 "swap_chequebook", // to not redeploy chequebook contract 205 "batchstore", // avoid unnecessary syncing 206 "transaction", // to not resync blockchain transactions 207 } 208 keys []string 209 err error 210 ) 211 212 keys, err = s.collectKeysExcept(prefixesToPreserve) 213 if err != nil { 214 return fmt.Errorf("collect keys except: %w", err) 215 } 216 return s.deleteKeys(keys) 217 } 218 219 func (s *StateStorerAdapter) collectKeysExcept(prefixesToPreserve []string) (keys []string, err error) { 220 if err := s.Iterate("", func(k, v []byte) (bool, error) { 221 stk := string(k) 222 has := false 223 for _, v := range prefixesToPreserve { 224 if strings.HasPrefix(stk, v) { 225 has = true 226 break 227 } 228 } 229 if !has { 230 keys = append(keys, stk) 231 } 232 return false, nil 233 }); err != nil { 234 return nil, err 235 } 236 return keys, nil 237 } 238 239 func (s *StateStorerAdapter) deleteKeys(keys []string) error { 240 for _, v := range keys { 241 err := s.Delete(v) 242 if err != nil { 243 return fmt.Errorf("deleting key %s: %w", v, err) 244 } 245 } 246 return nil 247 } 248 249 // NewStateStorerAdapter creates a new StateStorerAdapter. 250 func NewStateStorerAdapter(storage storage.Store) (*StateStorerAdapter, error) { 251 err := migration.Migrate(storage, "migration", allSteps(storage)) 252 if err != nil { 253 return nil, err 254 } 255 return &StateStorerAdapter{storage: storage}, nil 256 }