github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/swarm/storage/types.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package storage 18 19 import ( 20 "bytes" 21 "context" 22 "crypto" 23 "crypto/rand" 24 "encoding/binary" 25 "fmt" 26 "hash" 27 "io" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/crypto/sha3" 31 "github.com/ethereum/go-ethereum/swarm/bmt" 32 ch "github.com/ethereum/go-ethereum/swarm/chunk" 33 ) 34 35 const MaxPO = 16 36 const AddressLength = 32 37 38 type Hasher func() hash.Hash 39 type SwarmHasher func() SwarmHash 40 41 // Peer is the recorded as Source on the chunk 42 // should probably not be here? but network should wrap chunk object 43 type Peer interface{} 44 45 type Address []byte 46 47 func (a Address) Size() uint { 48 return uint(len(a)) 49 } 50 51 func (a Address) isEqual(y Address) bool { 52 return bytes.Equal(a, y) 53 } 54 55 func (a Address) bits(i, j uint) uint { 56 ii := i >> 3 57 jj := i & 7 58 if ii >= a.Size() { 59 return 0 60 } 61 62 if jj+j <= 8 { 63 return uint((a[ii] >> jj) & ((1 << j) - 1)) 64 } 65 66 res := uint(a[ii] >> jj) 67 jj = 8 - jj 68 j -= jj 69 for j != 0 { 70 ii++ 71 if j < 8 { 72 res += uint(a[ii]&((1<<j)-1)) << jj 73 return res 74 } 75 res += uint(a[ii]) << jj 76 jj += 8 77 j -= 8 78 } 79 return res 80 } 81 82 // Proximity(x, y) returns the proximity order of the MSB distance between x and y 83 // 84 // The distance metric MSB(x, y) of two equal length byte sequences x an y is the 85 // value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed. 86 // the binary cast is big endian: most significant bit first (=MSB). 87 // 88 // Proximity(x, y) is a discrete logarithmic scaling of the MSB distance. 89 // It is defined as the reverse rank of the integer part of the base 2 90 // logarithm of the distance. 91 // It is calculated by counting the number of common leading zeros in the (MSB) 92 // binary representation of the x^y. 93 // 94 // (0 farthest, 255 closest, 256 self) 95 func Proximity(one, other []byte) (ret int) { 96 b := (MaxPO-1)/8 + 1 97 if b > len(one) { 98 b = len(one) 99 } 100 m := 8 101 for i := 0; i < b; i++ { 102 oxo := one[i] ^ other[i] 103 if i == b-1 { 104 m = MaxPO % 8 105 } 106 for j := 0; j < m; j++ { 107 if (oxo>>uint8(7-j))&0x01 != 0 { 108 return i*8 + j 109 } 110 } 111 } 112 return MaxPO 113 } 114 115 func IsZeroAddr(addr Address) bool { 116 return len(addr) == 0 || bytes.Equal(addr, ZeroAddr) 117 } 118 119 var ZeroAddr = Address(common.Hash{}.Bytes()) 120 121 func MakeHashFunc(hash string) SwarmHasher { 122 switch hash { 123 case "SHA256": 124 return func() SwarmHash { return &HashWithLength{crypto.SHA256.New()} } 125 case "SHA3": 126 return func() SwarmHash { return &HashWithLength{sha3.NewKeccak256()} } 127 case "BMT": 128 return func() SwarmHash { 129 hasher := sha3.NewKeccak256 130 hasherSize := hasher().Size() 131 segmentCount := ch.DefaultSize / hasherSize 132 pool := bmt.NewTreePool(hasher, segmentCount, bmt.PoolSize) 133 return bmt.New(pool) 134 } 135 } 136 return nil 137 } 138 139 func (a Address) Hex() string { 140 return fmt.Sprintf("%064x", []byte(a[:])) 141 } 142 143 func (a Address) Log() string { 144 if len(a[:]) < 8 { 145 return fmt.Sprintf("%x", []byte(a[:])) 146 } 147 return fmt.Sprintf("%016x", []byte(a[:8])) 148 } 149 150 func (a Address) String() string { 151 return fmt.Sprintf("%064x", []byte(a)) 152 } 153 154 func (a Address) MarshalJSON() (out []byte, err error) { 155 return []byte(`"` + a.String() + `"`), nil 156 } 157 158 func (a *Address) UnmarshalJSON(value []byte) error { 159 s := string(value) 160 *a = make([]byte, 32) 161 h := common.Hex2Bytes(s[1 : len(s)-1]) 162 copy(*a, h) 163 return nil 164 } 165 166 type AddressCollection []Address 167 168 func NewAddressCollection(l int) AddressCollection { 169 return make(AddressCollection, l) 170 } 171 172 func (c AddressCollection) Len() int { 173 return len(c) 174 } 175 176 func (c AddressCollection) Less(i, j int) bool { 177 return bytes.Compare(c[i], c[j]) == -1 178 } 179 180 func (c AddressCollection) Swap(i, j int) { 181 c[i], c[j] = c[j], c[i] 182 } 183 184 // Chunk interface implemented by context.Contexts and data chunks 185 type Chunk interface { 186 Address() Address 187 Payload() []byte 188 SpanBytes() []byte 189 Span() int64 190 Data() []byte 191 } 192 193 type chunk struct { 194 addr Address 195 sdata []byte 196 span int64 197 } 198 199 func NewChunk(addr Address, data []byte) *chunk { 200 return &chunk{ 201 addr: addr, 202 sdata: data, 203 span: -1, 204 } 205 } 206 207 func (c *chunk) Address() Address { 208 return c.addr 209 } 210 211 func (c *chunk) SpanBytes() []byte { 212 return c.sdata[:8] 213 } 214 215 func (c *chunk) Span() int64 { 216 if c.span == -1 { 217 c.span = int64(binary.LittleEndian.Uint64(c.sdata[:8])) 218 } 219 return c.span 220 } 221 222 func (c *chunk) Data() []byte { 223 return c.sdata 224 } 225 226 func (c *chunk) Payload() []byte { 227 return c.sdata[8:] 228 } 229 230 // String() for pretty printing 231 func (self *chunk) String() string { 232 return fmt.Sprintf("Address: %v TreeSize: %v Chunksize: %v", self.addr.Log(), self.span, len(self.sdata)) 233 } 234 235 func GenerateRandomChunk(dataSize int64) Chunk { 236 hasher := MakeHashFunc(DefaultHash)() 237 sdata := make([]byte, dataSize+8) 238 rand.Read(sdata[8:]) 239 binary.LittleEndian.PutUint64(sdata[:8], uint64(dataSize)) 240 hasher.ResetWithLength(sdata[:8]) 241 hasher.Write(sdata[8:]) 242 return NewChunk(hasher.Sum(nil), sdata) 243 } 244 245 func GenerateRandomChunks(dataSize int64, count int) (chunks []Chunk) { 246 for i := 0; i < count; i++ { 247 ch := GenerateRandomChunk(dataSize) 248 chunks = append(chunks, ch) 249 } 250 return chunks 251 } 252 253 // Size, Seek, Read, ReadAt 254 type LazySectionReader interface { 255 Context() context.Context 256 Size(context.Context, chan bool) (int64, error) 257 io.Seeker 258 io.Reader 259 io.ReaderAt 260 } 261 262 type LazyTestSectionReader struct { 263 *io.SectionReader 264 } 265 266 func (r *LazyTestSectionReader) Size(context.Context, chan bool) (int64, error) { 267 return r.SectionReader.Size(), nil 268 } 269 270 func (r *LazyTestSectionReader) Context() context.Context { 271 return context.TODO() 272 } 273 274 type StoreParams struct { 275 Hash SwarmHasher `toml:"-"` 276 DbCapacity uint64 277 CacheCapacity uint 278 BaseKey []byte 279 } 280 281 func NewDefaultStoreParams() *StoreParams { 282 return NewStoreParams(defaultLDBCapacity, defaultCacheCapacity, nil, nil) 283 } 284 285 func NewStoreParams(ldbCap uint64, cacheCap uint, hash SwarmHasher, basekey []byte) *StoreParams { 286 if basekey == nil { 287 basekey = make([]byte, 32) 288 } 289 if hash == nil { 290 hash = MakeHashFunc(DefaultHash) 291 } 292 return &StoreParams{ 293 Hash: hash, 294 DbCapacity: ldbCap, 295 CacheCapacity: cacheCap, 296 BaseKey: basekey, 297 } 298 } 299 300 type ChunkData []byte 301 302 type Reference []byte 303 304 // Putter is responsible to store data and create a reference for it 305 type Putter interface { 306 Put(context.Context, ChunkData) (Reference, error) 307 // RefSize returns the length of the Reference created by this Putter 308 RefSize() int64 309 // Close is to indicate that no more chunk data will be Put on this Putter 310 Close() 311 // Wait returns if all data has been store and the Close() was called. 312 Wait(context.Context) error 313 } 314 315 // Getter is an interface to retrieve a chunk's data by its reference 316 type Getter interface { 317 Get(context.Context, Reference) (ChunkData, error) 318 } 319 320 // NOTE: this returns invalid data if chunk is encrypted 321 func (c ChunkData) Size() uint64 { 322 return binary.LittleEndian.Uint64(c[:8]) 323 } 324 325 func (c ChunkData) Data() []byte { 326 return c[8:] 327 } 328 329 type ChunkValidator interface { 330 Validate(addr Address, data []byte) bool 331 } 332 333 // Provides method for validation of content address in chunks 334 // Holds the corresponding hasher to create the address 335 type ContentAddressValidator struct { 336 Hasher SwarmHasher 337 } 338 339 // Constructor 340 func NewContentAddressValidator(hasher SwarmHasher) *ContentAddressValidator { 341 return &ContentAddressValidator{ 342 Hasher: hasher, 343 } 344 } 345 346 // Validate that the given key is a valid content address for the given data 347 func (v *ContentAddressValidator) Validate(addr Address, data []byte) bool { 348 if l := len(data); l < 9 || l > ch.DefaultSize+8 { 349 // log.Error("invalid chunk size", "chunk", addr.Hex(), "size", l) 350 return false 351 } 352 353 hasher := v.Hasher() 354 hasher.ResetWithLength(data[:8]) 355 hasher.Write(data[8:]) 356 hash := hasher.Sum(nil) 357 358 return bytes.Equal(hash, addr[:]) 359 } 360 361 type ChunkStore interface { 362 Put(ctx context.Context, ch Chunk) (err error) 363 Get(rctx context.Context, ref Address) (ch Chunk, err error) 364 Close() 365 } 366 367 // SyncChunkStore is a ChunkStore which supports syncing 368 type SyncChunkStore interface { 369 ChunkStore 370 BinIndex(po uint8) uint64 371 Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error 372 FetchFunc(ctx context.Context, ref Address) func(context.Context) error 373 } 374 375 // FakeChunkStore doesn't store anything, just implements the ChunkStore interface 376 // It can be used to inject into a hasherStore if you don't want to actually store data just do the 377 // hashing 378 type FakeChunkStore struct { 379 } 380 381 // Put doesn't store anything it is just here to implement ChunkStore 382 func (f *FakeChunkStore) Put(_ context.Context, ch Chunk) error { 383 return nil 384 } 385 386 // Gut doesn't store anything it is just here to implement ChunkStore 387 func (f *FakeChunkStore) Get(_ context.Context, ref Address) (Chunk, error) { 388 panic("FakeChunkStore doesn't support Get") 389 } 390 391 // Close doesn't store anything it is just here to implement ChunkStore 392 func (f *FakeChunkStore) Close() { 393 }