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