github.com/divan/go-ethereum@v1.8.14-0.20180820134928-1de9ada4016d/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 "sync" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/crypto/sha3" 32 "github.com/ethereum/go-ethereum/swarm/bmt" 33 "github.com/ethereum/go-ethereum/swarm/chunk" 34 ) 35 36 const MaxPO = 16 37 const KeyLength = 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 func Proximity(one, other []byte) (ret int) { 84 b := (MaxPO-1)/8 + 1 85 if b > len(one) { 86 b = len(one) 87 } 88 m := 8 89 for i := 0; i < b; i++ { 90 oxo := one[i] ^ other[i] 91 if i == b-1 { 92 m = MaxPO % 8 93 } 94 for j := 0; j < m; j++ { 95 if (oxo>>uint8(7-j))&0x01 != 0 { 96 return i*8 + j 97 } 98 } 99 } 100 return MaxPO 101 } 102 103 func IsZeroAddr(addr Address) bool { 104 return len(addr) == 0 || bytes.Equal(addr, ZeroAddr) 105 } 106 107 var ZeroAddr = Address(common.Hash{}.Bytes()) 108 109 func MakeHashFunc(hash string) SwarmHasher { 110 switch hash { 111 case "SHA256": 112 return func() SwarmHash { return &HashWithLength{crypto.SHA256.New()} } 113 case "SHA3": 114 return func() SwarmHash { return &HashWithLength{sha3.NewKeccak256()} } 115 case "BMT": 116 return func() SwarmHash { 117 hasher := sha3.NewKeccak256 118 hasherSize := hasher().Size() 119 segmentCount := chunk.DefaultSize / hasherSize 120 pool := bmt.NewTreePool(hasher, segmentCount, bmt.PoolSize) 121 return bmt.New(pool) 122 } 123 } 124 return nil 125 } 126 127 func (a Address) Hex() string { 128 return fmt.Sprintf("%064x", []byte(a[:])) 129 } 130 131 func (a Address) Log() string { 132 if len(a[:]) < 8 { 133 return fmt.Sprintf("%x", []byte(a[:])) 134 } 135 return fmt.Sprintf("%016x", []byte(a[:8])) 136 } 137 138 func (a Address) String() string { 139 return fmt.Sprintf("%064x", []byte(a)[:]) 140 } 141 142 func (a Address) MarshalJSON() (out []byte, err error) { 143 return []byte(`"` + a.String() + `"`), nil 144 } 145 146 func (a *Address) UnmarshalJSON(value []byte) error { 147 s := string(value) 148 *a = make([]byte, 32) 149 h := common.Hex2Bytes(s[1 : len(s)-1]) 150 copy(*a, h) 151 return nil 152 } 153 154 type AddressCollection []Address 155 156 func NewAddressCollection(l int) AddressCollection { 157 return make(AddressCollection, l) 158 } 159 160 func (c AddressCollection) Len() int { 161 return len(c) 162 } 163 164 func (c AddressCollection) Less(i, j int) bool { 165 return bytes.Compare(c[i], c[j]) == -1 166 } 167 168 func (c AddressCollection) Swap(i, j int) { 169 c[i], c[j] = c[j], c[i] 170 } 171 172 // Chunk also serves as a request object passed to ChunkStores 173 // in case it is a retrieval request, Data is nil and Size is 0 174 // Note that Size is not the size of the data chunk, which is Data.Size() 175 // but the size of the subtree encoded in the chunk 176 // 0 if request, to be supplied by the dpa 177 type Chunk struct { 178 Addr Address // always 179 SData []byte // nil if request, to be supplied by dpa 180 Size int64 // size of the data covered by the subtree encoded in this chunk 181 //Source Peer // peer 182 C chan bool // to signal data delivery by the dpa 183 ReqC chan bool // to signal the request done 184 dbStoredC chan bool // never remove a chunk from memStore before it is written to dbStore 185 dbStored bool 186 dbStoredMu *sync.Mutex 187 errored error // flag which is set when the chunk request has errored or timeouted 188 erroredMu sync.Mutex 189 } 190 191 func (c *Chunk) SetErrored(err error) { 192 c.erroredMu.Lock() 193 defer c.erroredMu.Unlock() 194 195 c.errored = err 196 } 197 198 func (c *Chunk) GetErrored() error { 199 c.erroredMu.Lock() 200 defer c.erroredMu.Unlock() 201 202 return c.errored 203 } 204 205 func NewChunk(addr Address, reqC chan bool) *Chunk { 206 return &Chunk{ 207 Addr: addr, 208 ReqC: reqC, 209 dbStoredC: make(chan bool), 210 dbStoredMu: &sync.Mutex{}, 211 } 212 } 213 214 func (c *Chunk) markAsStored() { 215 c.dbStoredMu.Lock() 216 defer c.dbStoredMu.Unlock() 217 218 if !c.dbStored { 219 close(c.dbStoredC) 220 c.dbStored = true 221 } 222 } 223 224 func (c *Chunk) WaitToStore() error { 225 <-c.dbStoredC 226 return c.GetErrored() 227 } 228 229 func GenerateRandomChunk(dataSize int64) *Chunk { 230 return GenerateRandomChunks(dataSize, 1)[0] 231 } 232 233 func GenerateRandomChunks(dataSize int64, count int) (chunks []*Chunk) { 234 var i int 235 hasher := MakeHashFunc(DefaultHash)() 236 if dataSize > chunk.DefaultSize { 237 dataSize = chunk.DefaultSize 238 } 239 240 for i = 0; i < count; i++ { 241 chunks = append(chunks, NewChunk(nil, nil)) 242 chunks[i].SData = make([]byte, dataSize+8) 243 rand.Read(chunks[i].SData) 244 binary.LittleEndian.PutUint64(chunks[i].SData[:8], uint64(dataSize)) 245 hasher.ResetWithLength(chunks[i].SData[:8]) 246 hasher.Write(chunks[i].SData[8:]) 247 chunks[i].Addr = make([]byte, 32) 248 copy(chunks[i].Addr, hasher.Sum(nil)) 249 } 250 251 return chunks 252 } 253 254 // Size, Seek, Read, ReadAt 255 type LazySectionReader interface { 256 Context() context.Context 257 Size(context.Context, chan bool) (int64, error) 258 io.Seeker 259 io.Reader 260 io.ReaderAt 261 } 262 263 type LazyTestSectionReader struct { 264 *io.SectionReader 265 } 266 267 func (r *LazyTestSectionReader) Size(context.Context, chan bool) (int64, error) { 268 return r.SectionReader.Size(), nil 269 } 270 271 func (r *LazyTestSectionReader) Context() context.Context { 272 return context.TODO() 273 } 274 275 type StoreParams struct { 276 Hash SwarmHasher `toml:"-"` 277 DbCapacity uint64 278 CacheCapacity uint 279 ChunkRequestsCacheCapacity uint 280 BaseKey []byte 281 } 282 283 func NewDefaultStoreParams() *StoreParams { 284 return NewStoreParams(defaultLDBCapacity, defaultCacheCapacity, defaultChunkRequestsCacheCapacity, nil, nil) 285 } 286 287 func NewStoreParams(ldbCap uint64, cacheCap uint, requestsCap uint, hash SwarmHasher, basekey []byte) *StoreParams { 288 if basekey == nil { 289 basekey = make([]byte, 32) 290 } 291 if hash == nil { 292 hash = MakeHashFunc(DefaultHash) 293 } 294 return &StoreParams{ 295 Hash: hash, 296 DbCapacity: ldbCap, 297 CacheCapacity: cacheCap, 298 ChunkRequestsCacheCapacity: requestsCap, 299 BaseKey: basekey, 300 } 301 } 302 303 type ChunkData []byte 304 305 type Reference []byte 306 307 // Putter is responsible to store data and create a reference for it 308 type Putter interface { 309 Put(context.Context, ChunkData) (Reference, error) 310 // RefSize returns the length of the Reference created by this Putter 311 RefSize() int64 312 // Close is to indicate that no more chunk data will be Put on this Putter 313 Close() 314 // Wait returns if all data has been store and the Close() was called. 315 Wait(context.Context) error 316 } 317 318 // Getter is an interface to retrieve a chunk's data by its reference 319 type Getter interface { 320 Get(context.Context, Reference) (ChunkData, error) 321 } 322 323 // NOTE: this returns invalid data if chunk is encrypted 324 func (c ChunkData) Size() int64 { 325 return int64(binary.LittleEndian.Uint64(c[:8])) 326 } 327 328 func (c ChunkData) Data() []byte { 329 return c[8:] 330 } 331 332 type ChunkValidator interface { 333 Validate(addr Address, data []byte) bool 334 } 335 336 // Provides method for validation of content address in chunks 337 // Holds the corresponding hasher to create the address 338 type ContentAddressValidator struct { 339 Hasher SwarmHasher 340 } 341 342 // Constructor 343 func NewContentAddressValidator(hasher SwarmHasher) *ContentAddressValidator { 344 return &ContentAddressValidator{ 345 Hasher: hasher, 346 } 347 } 348 349 // Validate that the given key is a valid content address for the given data 350 func (v *ContentAddressValidator) Validate(addr Address, data []byte) bool { 351 if l := len(data); l < 9 || l > chunk.DefaultSize+8 { 352 return false 353 } 354 355 hasher := v.Hasher() 356 hasher.ResetWithLength(data[:8]) 357 hasher.Write(data[8:]) 358 hash := hasher.Sum(nil) 359 360 return bytes.Equal(hash, addr[:]) 361 }