github.com/daragao/go-ethereum@v1.8.14-0.20180809141559-45eaef243198/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 ) 34 35 const MaxPO = 16 36 const KeyLength = 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 func Proximity(one, other []byte) (ret int) { 83 b := (MaxPO-1)/8 + 1 84 if b > len(one) { 85 b = len(one) 86 } 87 m := 8 88 for i := 0; i < b; i++ { 89 oxo := one[i] ^ other[i] 90 if i == b-1 { 91 m = MaxPO % 8 92 } 93 for j := 0; j < m; j++ { 94 if (oxo>>uint8(7-j))&0x01 != 0 { 95 return i*8 + j 96 } 97 } 98 } 99 return MaxPO 100 } 101 102 func IsZeroAddr(addr Address) bool { 103 return len(addr) == 0 || bytes.Equal(addr, ZeroAddr) 104 } 105 106 var ZeroAddr = Address(common.Hash{}.Bytes()) 107 108 func MakeHashFunc(hash string) SwarmHasher { 109 switch hash { 110 case "SHA256": 111 return func() SwarmHash { return &HashWithLength{crypto.SHA256.New()} } 112 case "SHA3": 113 return func() SwarmHash { return &HashWithLength{sha3.NewKeccak256()} } 114 case "BMT": 115 return func() SwarmHash { 116 hasher := sha3.NewKeccak256 117 pool := bmt.NewTreePool(hasher, bmt.SegmentCount, bmt.PoolSize) 118 return bmt.New(pool) 119 } 120 } 121 return nil 122 } 123 124 func (a Address) Hex() string { 125 return fmt.Sprintf("%064x", []byte(a[:])) 126 } 127 128 func (a Address) Log() string { 129 if len(a[:]) < 8 { 130 return fmt.Sprintf("%x", []byte(a[:])) 131 } 132 return fmt.Sprintf("%016x", []byte(a[:8])) 133 } 134 135 func (a Address) String() string { 136 return fmt.Sprintf("%064x", []byte(a)[:]) 137 } 138 139 func (a Address) MarshalJSON() (out []byte, err error) { 140 return []byte(`"` + a.String() + `"`), nil 141 } 142 143 func (a *Address) UnmarshalJSON(value []byte) error { 144 s := string(value) 145 *a = make([]byte, 32) 146 h := common.Hex2Bytes(s[1 : len(s)-1]) 147 copy(*a, h) 148 return nil 149 } 150 151 type AddressCollection []Address 152 153 func NewAddressCollection(l int) AddressCollection { 154 return make(AddressCollection, l) 155 } 156 157 func (c AddressCollection) Len() int { 158 return len(c) 159 } 160 161 func (c AddressCollection) Less(i, j int) bool { 162 return bytes.Compare(c[i], c[j]) == -1 163 } 164 165 func (c AddressCollection) Swap(i, j int) { 166 c[i], c[j] = c[j], c[i] 167 } 168 169 // Chunk also serves as a request object passed to ChunkStores 170 // in case it is a retrieval request, Data is nil and Size is 0 171 // Note that Size is not the size of the data chunk, which is Data.Size() 172 // but the size of the subtree encoded in the chunk 173 // 0 if request, to be supplied by the dpa 174 type Chunk struct { 175 Addr Address // always 176 SData []byte // nil if request, to be supplied by dpa 177 Size int64 // size of the data covered by the subtree encoded in this chunk 178 //Source Peer // peer 179 C chan bool // to signal data delivery by the dpa 180 ReqC chan bool // to signal the request done 181 dbStoredC chan bool // never remove a chunk from memStore before it is written to dbStore 182 dbStored bool 183 dbStoredMu *sync.Mutex 184 errored error // flag which is set when the chunk request has errored or timeouted 185 erroredMu sync.Mutex 186 } 187 188 func (c *Chunk) SetErrored(err error) { 189 c.erroredMu.Lock() 190 defer c.erroredMu.Unlock() 191 192 c.errored = err 193 } 194 195 func (c *Chunk) GetErrored() error { 196 c.erroredMu.Lock() 197 defer c.erroredMu.Unlock() 198 199 return c.errored 200 } 201 202 func NewChunk(addr Address, reqC chan bool) *Chunk { 203 return &Chunk{ 204 Addr: addr, 205 ReqC: reqC, 206 dbStoredC: make(chan bool), 207 dbStoredMu: &sync.Mutex{}, 208 } 209 } 210 211 func (c *Chunk) markAsStored() { 212 c.dbStoredMu.Lock() 213 defer c.dbStoredMu.Unlock() 214 215 if !c.dbStored { 216 close(c.dbStoredC) 217 c.dbStored = true 218 } 219 } 220 221 func (c *Chunk) WaitToStore() error { 222 <-c.dbStoredC 223 return c.GetErrored() 224 } 225 226 func GenerateRandomChunk(dataSize int64) *Chunk { 227 return GenerateRandomChunks(dataSize, 1)[0] 228 } 229 230 func GenerateRandomChunks(dataSize int64, count int) (chunks []*Chunk) { 231 var i int 232 hasher := MakeHashFunc(DefaultHash)() 233 if dataSize > DefaultChunkSize { 234 dataSize = DefaultChunkSize 235 } 236 237 for i = 0; i < count; i++ { 238 chunks = append(chunks, NewChunk(nil, nil)) 239 chunks[i].SData = make([]byte, dataSize+8) 240 rand.Read(chunks[i].SData) 241 binary.LittleEndian.PutUint64(chunks[i].SData[:8], uint64(dataSize)) 242 hasher.ResetWithLength(chunks[i].SData[:8]) 243 hasher.Write(chunks[i].SData[8:]) 244 chunks[i].Addr = make([]byte, 32) 245 copy(chunks[i].Addr, hasher.Sum(nil)) 246 } 247 248 return chunks 249 } 250 251 // Size, Seek, Read, ReadAt 252 type LazySectionReader interface { 253 Context() context.Context 254 Size(context.Context, chan bool) (int64, error) 255 io.Seeker 256 io.Reader 257 io.ReaderAt 258 } 259 260 type LazyTestSectionReader struct { 261 *io.SectionReader 262 } 263 264 func (r *LazyTestSectionReader) Size(context.Context, chan bool) (int64, error) { 265 return r.SectionReader.Size(), nil 266 } 267 268 func (r *LazyTestSectionReader) Context() context.Context { 269 return context.TODO() 270 } 271 272 type StoreParams struct { 273 Hash SwarmHasher `toml:"-"` 274 DbCapacity uint64 275 CacheCapacity uint 276 ChunkRequestsCacheCapacity uint 277 BaseKey []byte 278 } 279 280 func NewDefaultStoreParams() *StoreParams { 281 return NewStoreParams(defaultLDBCapacity, defaultCacheCapacity, defaultChunkRequestsCacheCapacity, nil, nil) 282 } 283 284 func NewStoreParams(ldbCap uint64, cacheCap uint, requestsCap uint, hash SwarmHasher, basekey []byte) *StoreParams { 285 if basekey == nil { 286 basekey = make([]byte, 32) 287 } 288 if hash == nil { 289 hash = MakeHashFunc(DefaultHash) 290 } 291 return &StoreParams{ 292 Hash: hash, 293 DbCapacity: ldbCap, 294 CacheCapacity: cacheCap, 295 ChunkRequestsCacheCapacity: requestsCap, 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() int64 { 322 return int64(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 hasher := v.Hasher() 349 hasher.ResetWithLength(data[:8]) 350 hasher.Write(data[8:]) 351 hash := hasher.Sum(nil) 352 353 return bytes.Equal(hash, addr[:]) 354 }