github.com/ethersphere/bee/v2@v2.2.0/pkg/storer/internal/reserve/items.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 reserve 6 7 import ( 8 "encoding/binary" 9 "errors" 10 "path" 11 12 "github.com/ethersphere/bee/v2/pkg/storage" 13 "github.com/ethersphere/bee/v2/pkg/swarm" 14 ) 15 16 var ( 17 errMarshalInvalidAddress = errors.New("marshal: invalid address") 18 errUnmarshalInvalidSize = errors.New("unmarshal: invalid size") 19 ) 20 21 // BatchRadiusItem allows iteration of the chunks with respect to bin and batchID. 22 // Used for batch evictions of certain bins. 23 type BatchRadiusItem struct { 24 Bin uint8 25 BatchID []byte 26 StampHash []byte 27 Address swarm.Address 28 BinID uint64 29 } 30 31 func (b *BatchRadiusItem) Namespace() string { 32 return "batchRadius" 33 } 34 35 // batchID/bin/ChunkAddr/stampHash 36 func (b *BatchRadiusItem) ID() string { 37 return string(b.BatchID) + string(b.Bin) + b.Address.ByteString() + string(b.StampHash) 38 } 39 40 func (b *BatchRadiusItem) String() string { 41 return path.Join(b.Namespace(), b.ID()) 42 } 43 44 func (b *BatchRadiusItem) Clone() storage.Item { 45 if b == nil { 46 return nil 47 } 48 return &BatchRadiusItem{ 49 Bin: b.Bin, 50 BatchID: copyBytes(b.BatchID), 51 Address: b.Address.Clone(), 52 BinID: b.BinID, 53 StampHash: copyBytes(b.StampHash), 54 } 55 } 56 57 const batchRadiusItemSize = 1 + swarm.HashSize + swarm.HashSize + 8 + swarm.HashSize 58 59 func (b *BatchRadiusItem) Marshal() ([]byte, error) { 60 61 if b.Address.IsZero() { 62 return nil, errMarshalInvalidAddress 63 } 64 65 buf := make([]byte, batchRadiusItemSize) 66 67 i := 0 68 69 buf[i] = b.Bin 70 i += 1 71 72 copy(buf[i:i+swarm.HashSize], b.BatchID) 73 i += swarm.HashSize 74 75 copy(buf[i:i+swarm.HashSize], b.Address.Bytes()) 76 i += swarm.HashSize 77 78 binary.BigEndian.PutUint64(buf[i:i+8], b.BinID) 79 i += 8 80 81 copy(buf[i:i+swarm.HashSize], b.StampHash) 82 return buf, nil 83 } 84 85 func (b *BatchRadiusItem) Unmarshal(buf []byte) error { 86 87 if len(buf) != batchRadiusItemSize { 88 return errUnmarshalInvalidSize 89 } 90 91 i := 0 92 b.Bin = buf[i] 93 i += 1 94 95 b.BatchID = copyBytes(buf[i : i+swarm.HashSize]) 96 i += swarm.HashSize 97 98 b.Address = swarm.NewAddress(buf[i : i+swarm.HashSize]).Clone() 99 i += swarm.HashSize 100 101 b.BinID = binary.BigEndian.Uint64(buf[i : i+8]) 102 i += 8 103 104 b.StampHash = copyBytes(buf[i : i+swarm.HashSize]) 105 return nil 106 } 107 108 // ChunkBinItem allows for iterating on ranges of bin and binIDs for chunks. 109 // BinIDs come in handy when syncing the reserve contents with other peers. 110 type ChunkBinItem struct { 111 Bin uint8 112 BinID uint64 113 Address swarm.Address 114 BatchID []byte 115 StampHash []byte 116 ChunkType swarm.ChunkType 117 } 118 119 func (c *ChunkBinItem) Namespace() string { 120 return "chunkBin" 121 } 122 123 // bin/binID 124 func (c *ChunkBinItem) ID() string { 125 return binIDToString(c.Bin, c.BinID) 126 } 127 128 func binIDToString(bin uint8, binID uint64) string { 129 binIDBytes := make([]byte, 8) 130 binary.BigEndian.PutUint64(binIDBytes, binID) 131 return string(bin) + string(binIDBytes) 132 } 133 134 func (c *ChunkBinItem) String() string { 135 return path.Join(c.Namespace(), c.ID()) 136 } 137 138 func (c *ChunkBinItem) Clone() storage.Item { 139 if c == nil { 140 return nil 141 } 142 return &ChunkBinItem{ 143 Bin: c.Bin, 144 BinID: c.BinID, 145 Address: c.Address.Clone(), 146 BatchID: copyBytes(c.BatchID), 147 StampHash: copyBytes(c.StampHash), 148 ChunkType: c.ChunkType, 149 } 150 } 151 152 const chunkBinItemSize = 1 + 8 + swarm.HashSize + swarm.HashSize + 1 + swarm.HashSize 153 154 func (c *ChunkBinItem) Marshal() ([]byte, error) { 155 156 if c.Address.IsZero() { 157 return nil, errMarshalInvalidAddress 158 } 159 160 buf := make([]byte, chunkBinItemSize) 161 i := 0 162 163 buf[i] = c.Bin 164 i += 1 165 166 binary.BigEndian.PutUint64(buf[i:i+8], c.BinID) 167 i += 8 168 169 copy(buf[i:i+swarm.HashSize], c.Address.Bytes()) 170 i += swarm.HashSize 171 172 copy(buf[i:i+swarm.HashSize], c.BatchID) 173 i += swarm.HashSize 174 175 buf[i] = uint8(c.ChunkType) 176 i += 1 177 178 copy(buf[i:i+swarm.HashSize], c.StampHash) 179 return buf, nil 180 } 181 182 func (c *ChunkBinItem) Unmarshal(buf []byte) error { 183 184 if len(buf) != chunkBinItemSize { 185 return errUnmarshalInvalidSize 186 } 187 188 i := 0 189 c.Bin = buf[i] 190 i += 1 191 192 c.BinID = binary.BigEndian.Uint64(buf[i : i+8]) 193 i += 8 194 195 c.Address = swarm.NewAddress(buf[i : i+swarm.HashSize]).Clone() 196 i += swarm.HashSize 197 198 c.BatchID = copyBytes(buf[i : i+swarm.HashSize]) 199 i += swarm.HashSize 200 201 c.ChunkType = swarm.ChunkType(buf[i]) 202 i += 1 203 204 c.StampHash = copyBytes(buf[i : i+swarm.HashSize]) 205 return nil 206 } 207 208 // BinItem stores the latest binIDs for each bin between 0 and swarm.MaxBins 209 type BinItem struct { 210 Bin uint8 211 BinID uint64 212 } 213 214 func (b *BinItem) Namespace() string { 215 return "binID" 216 } 217 218 func (b *BinItem) ID() string { 219 return string(b.Bin) 220 } 221 222 func (c *BinItem) String() string { 223 return path.Join(c.Namespace(), c.ID()) 224 } 225 func (b *BinItem) Clone() storage.Item { 226 if b == nil { 227 return nil 228 } 229 return &BinItem{ 230 Bin: b.Bin, 231 BinID: b.BinID, 232 } 233 } 234 235 const binItemSize = 8 236 237 func (c *BinItem) Marshal() ([]byte, error) { 238 buf := make([]byte, binItemSize) 239 binary.BigEndian.PutUint64(buf, c.BinID) 240 return buf, nil 241 } 242 243 func (c *BinItem) Unmarshal(buf []byte) error { 244 if len(buf) != binItemSize { 245 return errUnmarshalInvalidSize 246 } 247 c.BinID = binary.BigEndian.Uint64(buf) 248 return nil 249 } 250 251 // EpochItem stores the timestamp in seconds of the initial creation of the reserve. 252 type EpochItem struct { 253 Timestamp uint64 254 } 255 256 func (e *EpochItem) Namespace() string { return "epochItem" } 257 func (e *EpochItem) ID() string { return "" } 258 func (e *EpochItem) String() string { return e.Namespace() } 259 func (e *EpochItem) Clone() storage.Item { return &EpochItem{e.Timestamp} } 260 261 const epochItemSize = 8 262 263 func (e *EpochItem) Marshal() ([]byte, error) { 264 buf := make([]byte, epochItemSize) 265 binary.BigEndian.PutUint64(buf, e.Timestamp) 266 return buf, nil 267 } 268 269 func (e *EpochItem) Unmarshal(buf []byte) error { 270 if len(buf) != epochItemSize { 271 return errUnmarshalInvalidSize 272 } 273 e.Timestamp = binary.BigEndian.Uint64(buf) 274 return nil 275 } 276 277 // radiusItem stores the current storage radius of the reserve. 278 type radiusItem struct { 279 Radius uint8 280 } 281 282 func (r *radiusItem) Namespace() string { 283 return "radius" 284 } 285 286 func (r *radiusItem) ID() string { 287 return "" 288 } 289 290 func (r *radiusItem) String() string { 291 return r.Namespace() 292 } 293 294 func (r *radiusItem) Clone() storage.Item { 295 if r == nil { 296 return nil 297 } 298 return &radiusItem{ 299 Radius: r.Radius, 300 } 301 } 302 303 func (r *radiusItem) Marshal() ([]byte, error) { 304 return []byte{r.Radius}, nil 305 } 306 307 func (r *radiusItem) Unmarshal(buf []byte) error { 308 if len(buf) != 1 { 309 return errUnmarshalInvalidSize 310 } 311 r.Radius = buf[0] 312 return nil 313 } 314 315 func copyBytes(src []byte) []byte { 316 if src == nil { 317 return nil 318 } 319 dst := make([]byte, len(src)) 320 copy(dst, src) 321 return dst 322 }