github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/mru/handler.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:50</date> 10 //</624342683002867712> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 // 29 // 30 package mru 31 32 import ( 33 "bytes" 34 "context" 35 "sync" 36 "time" 37 "unsafe" 38 39 "github.com/ethereum/go-ethereum/swarm/chunk" 40 "github.com/ethereum/go-ethereum/swarm/log" 41 "github.com/ethereum/go-ethereum/swarm/storage" 42 ) 43 44 type Handler struct { 45 chunkStore *storage.NetStore 46 HashSize int 47 resources map[uint64]*resource 48 resourceLock sync.RWMutex 49 storeTimeout time.Duration 50 queryMaxPeriods uint32 51 } 52 53 // 54 // 55 type HandlerParams struct { 56 QueryMaxPeriods uint32 57 } 58 59 // 60 var hashPool sync.Pool 61 var minimumChunkLength int 62 63 // 64 func init() { 65 hashPool = sync.Pool{ 66 New: func() interface{} { 67 return storage.MakeHashFunc(resourceHashAlgorithm)() 68 }, 69 } 70 if minimumMetadataLength < minimumUpdateDataLength { 71 minimumChunkLength = minimumMetadataLength 72 } else { 73 minimumChunkLength = minimumUpdateDataLength 74 } 75 } 76 77 // 78 func NewHandler(params *HandlerParams) *Handler { 79 rh := &Handler{ 80 resources: make(map[uint64]*resource), 81 storeTimeout: defaultStoreTimeout, 82 queryMaxPeriods: params.QueryMaxPeriods, 83 } 84 85 for i := 0; i < hasherCount; i++ { 86 hashfunc := storage.MakeHashFunc(resourceHashAlgorithm)() 87 if rh.HashSize == 0 { 88 rh.HashSize = hashfunc.Size() 89 } 90 hashPool.Put(hashfunc) 91 } 92 93 return rh 94 } 95 96 // 97 func (h *Handler) SetStore(store *storage.NetStore) { 98 h.chunkStore = store 99 } 100 101 // 102 // 103 // 104 func (h *Handler) Validate(chunkAddr storage.Address, data []byte) bool { 105 dataLength := len(data) 106 if dataLength < minimumChunkLength || dataLength > chunk.DefaultSize+8 { 107 return false 108 } 109 110 // 111 if data[0] == 0 && data[1] == 0 && dataLength >= minimumMetadataLength { 112 // 113 rootAddr, _ := metadataHash(data) 114 valid := bytes.Equal(chunkAddr, rootAddr) 115 if !valid { 116 log.Debug("Invalid root metadata chunk with address", "addr", chunkAddr.Hex()) 117 } 118 return valid 119 } 120 121 // 122 // 123 // 124 125 // 126 var r SignedResourceUpdate 127 if err := r.fromChunk(chunkAddr, data); err != nil { 128 log.Debug("Invalid resource chunk", "addr", chunkAddr.Hex(), "err", err.Error()) 129 return false 130 } 131 132 // 133 // 134 // 135 if !bytes.Equal(chunkAddr, r.updateHeader.UpdateAddr()) { 136 log.Debug("period,version,rootAddr contained in update chunk do not match updateAddr", "addr", chunkAddr.Hex()) 137 return false 138 } 139 140 // 141 // 142 // 143 if err := r.Verify(); err != nil { 144 log.Debug("Invalid signature", "err", err) 145 return false 146 } 147 148 return true 149 } 150 151 // 152 func (h *Handler) GetContent(rootAddr storage.Address) (storage.Address, []byte, error) { 153 rsrc := h.get(rootAddr) 154 if rsrc == nil || !rsrc.isSynced() { 155 return nil, nil, NewError(ErrNotFound, " does not exist or is not synced") 156 } 157 return rsrc.lastKey, rsrc.data, nil 158 } 159 160 // 161 func (h *Handler) GetLastPeriod(rootAddr storage.Address) (uint32, error) { 162 rsrc := h.get(rootAddr) 163 if rsrc == nil { 164 return 0, NewError(ErrNotFound, " does not exist") 165 } else if !rsrc.isSynced() { 166 return 0, NewError(ErrNotSynced, " is not synced") 167 } 168 return rsrc.period, nil 169 } 170 171 // 172 func (h *Handler) GetVersion(rootAddr storage.Address) (uint32, error) { 173 rsrc := h.get(rootAddr) 174 if rsrc == nil { 175 return 0, NewError(ErrNotFound, " does not exist") 176 } else if !rsrc.isSynced() { 177 return 0, NewError(ErrNotSynced, " is not synced") 178 } 179 return rsrc.version, nil 180 } 181 182 // 183 func (h *Handler) New(ctx context.Context, request *Request) error { 184 185 // 186 if request.metadata.Frequency == 0 { 187 return NewError(ErrInvalidValue, "frequency cannot be 0 when creating a resource") 188 } 189 190 // 191 if request.metadata.Owner == zeroAddr { 192 return NewError(ErrInvalidValue, "ownerAddr must be set to create a new metadata chunk") 193 } 194 195 // 196 chunk, metaHash, err := request.metadata.newChunk() 197 if err != nil { 198 return err 199 } 200 if request.metaHash != nil && !bytes.Equal(request.metaHash, metaHash) || 201 request.rootAddr != nil && !bytes.Equal(request.rootAddr, chunk.Addr) { 202 return NewError(ErrInvalidValue, "metaHash in UpdateRequest does not match actual metadata") 203 } 204 205 request.metaHash = metaHash 206 request.rootAddr = chunk.Addr 207 208 h.chunkStore.Put(ctx, chunk) 209 log.Debug("new resource", "name", request.metadata.Name, "startTime", request.metadata.StartTime, "frequency", request.metadata.Frequency, "owner", request.metadata.Owner) 210 211 // 212 rsrc := &resource{ 213 resourceUpdate: resourceUpdate{ 214 updateHeader: updateHeader{ 215 UpdateLookup: UpdateLookup{ 216 rootAddr: chunk.Addr, 217 }, 218 }, 219 }, 220 ResourceMetadata: request.metadata, 221 updated: time.Now(), 222 } 223 h.set(chunk.Addr, rsrc) 224 225 return nil 226 } 227 228 // 229 // 230 // 231 func (h *Handler) NewUpdateRequest(ctx context.Context, rootAddr storage.Address) (updateRequest *Request, err error) { 232 233 if rootAddr == nil { 234 return nil, NewError(ErrInvalidValue, "rootAddr cannot be nil") 235 } 236 237 // 238 rsrc, err := h.Load(ctx, rootAddr) 239 if err != nil { 240 return nil, err 241 } 242 243 now := TimestampProvider.Now() 244 245 updateRequest = new(Request) 246 updateRequest.period, err = getNextPeriod(rsrc.StartTime.Time, now.Time, rsrc.Frequency) 247 if err != nil { 248 return nil, err 249 } 250 251 if _, err = h.lookup(rsrc, LookupLatestVersionInPeriod(rsrc.rootAddr, updateRequest.period)); err != nil { 252 if err.(*Error).code != ErrNotFound { 253 return nil, err 254 } 255 // 256 // 257 } 258 259 updateRequest.multihash = rsrc.multihash 260 updateRequest.rootAddr = rsrc.rootAddr 261 updateRequest.metaHash = rsrc.metaHash 262 updateRequest.metadata = rsrc.ResourceMetadata 263 264 // 265 // 266 if h.hasUpdate(rootAddr, updateRequest.period) { 267 updateRequest.version = rsrc.version + 1 268 } else { 269 updateRequest.version = 1 270 } 271 272 return updateRequest, nil 273 } 274 275 // 276 // 277 // 278 // 279 // 280 // 281 // 282 func (h *Handler) Lookup(ctx context.Context, params *LookupParams) (*resource, error) { 283 284 rsrc := h.get(params.rootAddr) 285 if rsrc == nil { 286 return nil, NewError(ErrNothingToReturn, "resource not loaded") 287 } 288 return h.lookup(rsrc, params) 289 } 290 291 // 292 // 293 // 294 // 295 func (h *Handler) LookupPrevious(ctx context.Context, params *LookupParams) (*resource, error) { 296 rsrc := h.get(params.rootAddr) 297 if rsrc == nil { 298 return nil, NewError(ErrNothingToReturn, "resource not loaded") 299 } 300 if !rsrc.isSynced() { 301 return nil, NewError(ErrNotSynced, "LookupPrevious requires synced resource.") 302 } else if rsrc.period == 0 { 303 return nil, NewError(ErrNothingToReturn, " not found") 304 } 305 var version, period uint32 306 if rsrc.version > 1 { 307 version = rsrc.version - 1 308 period = rsrc.period 309 } else if rsrc.period == 1 { 310 return nil, NewError(ErrNothingToReturn, "Current update is the oldest") 311 } else { 312 version = 0 313 period = rsrc.period - 1 314 } 315 return h.lookup(rsrc, NewLookupParams(rsrc.rootAddr, period, version, params.Limit)) 316 } 317 318 // 319 func (h *Handler) lookup(rsrc *resource, params *LookupParams) (*resource, error) { 320 321 lp := *params 322 // 323 if h.chunkStore == nil { 324 return nil, NewError(ErrInit, "Call Handler.SetStore() before performing lookups") 325 } 326 327 var specificperiod bool 328 if lp.period > 0 { 329 specificperiod = true 330 } else { 331 // 332 now := TimestampProvider.Now() 333 334 var period uint32 335 period, err := getNextPeriod(rsrc.StartTime.Time, now.Time, rsrc.Frequency) 336 if err != nil { 337 return nil, err 338 } 339 lp.period = period 340 } 341 342 // 343 // 344 // 345 var specificversion bool 346 if lp.version > 0 { 347 specificversion = true 348 } else { 349 lp.version = 1 350 } 351 352 var hops uint32 353 if lp.Limit == 0 { 354 lp.Limit = h.queryMaxPeriods 355 } 356 log.Trace("resource lookup", "period", lp.period, "version", lp.version, "limit", lp.Limit) 357 for lp.period > 0 { 358 if lp.Limit != 0 && hops > lp.Limit { 359 return nil, NewErrorf(ErrPeriodDepth, "Lookup exceeded max period hops (%d)", lp.Limit) 360 } 361 updateAddr := lp.UpdateAddr() 362 chunk, err := h.chunkStore.GetWithTimeout(context.TODO(), updateAddr, defaultRetrieveTimeout) 363 if err == nil { 364 if specificversion { 365 return h.updateIndex(rsrc, chunk) 366 } 367 // 368 log.Trace("rsrc update version 1 found, checking for version updates", "period", lp.period, "updateAddr", updateAddr) 369 for { 370 newversion := lp.version + 1 371 updateAddr := lp.UpdateAddr() 372 newchunk, err := h.chunkStore.GetWithTimeout(context.TODO(), updateAddr, defaultRetrieveTimeout) 373 if err != nil { 374 return h.updateIndex(rsrc, chunk) 375 } 376 chunk = newchunk 377 lp.version = newversion 378 log.Trace("version update found, checking next", "version", lp.version, "period", lp.period, "updateAddr", updateAddr) 379 } 380 } 381 if specificperiod { 382 break 383 } 384 log.Trace("rsrc update not found, checking previous period", "period", lp.period, "updateAddr", updateAddr) 385 lp.period-- 386 hops++ 387 } 388 return nil, NewError(ErrNotFound, "no updates found") 389 } 390 391 // 392 // 393 func (h *Handler) Load(ctx context.Context, rootAddr storage.Address) (*resource, error) { 394 chunk, err := h.chunkStore.GetWithTimeout(ctx, rootAddr, defaultRetrieveTimeout) 395 if err != nil { 396 return nil, NewError(ErrNotFound, err.Error()) 397 } 398 399 // 400 rsrc := &resource{} 401 402 if err := rsrc.ResourceMetadata.binaryGet(chunk.SData); err != nil { // 403 return nil, err 404 } 405 406 rsrc.rootAddr, rsrc.metaHash = metadataHash(chunk.SData) 407 if !bytes.Equal(rsrc.rootAddr, rootAddr) { 408 return nil, NewError(ErrCorruptData, "Corrupt metadata chunk") 409 } 410 h.set(rootAddr, rsrc) 411 log.Trace("resource index load", "rootkey", rootAddr, "name", rsrc.ResourceMetadata.Name, "starttime", rsrc.ResourceMetadata.StartTime, "frequency", rsrc.ResourceMetadata.Frequency) 412 return rsrc, nil 413 } 414 415 // 416 func (h *Handler) updateIndex(rsrc *resource, chunk *storage.Chunk) (*resource, error) { 417 418 // 419 var r SignedResourceUpdate 420 if err := r.fromChunk(chunk.Addr, chunk.SData); err != nil { 421 return nil, err 422 } 423 log.Trace("resource index update", "name", rsrc.ResourceMetadata.Name, "updatekey", chunk.Addr, "period", r.period, "version", r.version) 424 425 // 426 rsrc.lastKey = chunk.Addr 427 rsrc.period = r.period 428 rsrc.version = r.version 429 rsrc.updated = time.Now() 430 rsrc.data = make([]byte, len(r.data)) 431 rsrc.multihash = r.multihash 432 copy(rsrc.data, r.data) 433 rsrc.Reader = bytes.NewReader(rsrc.data) 434 log.Debug("resource synced", "name", rsrc.ResourceMetadata.Name, "updateAddr", chunk.Addr, "period", rsrc.period, "version", rsrc.version) 435 h.set(chunk.Addr, rsrc) 436 return rsrc, nil 437 } 438 439 // 440 // 441 // 442 // 443 // 444 // 445 func (h *Handler) Update(ctx context.Context, r *SignedResourceUpdate) (storage.Address, error) { 446 return h.update(ctx, r) 447 } 448 449 // 450 func (h *Handler) update(ctx context.Context, r *SignedResourceUpdate) (updateAddr storage.Address, err error) { 451 452 // 453 if h.chunkStore == nil { 454 return nil, NewError(ErrInit, "Call Handler.SetStore() before updating") 455 } 456 457 rsrc := h.get(r.rootAddr) 458 if rsrc != nil && rsrc.period != 0 && rsrc.version != 0 && // 459 rsrc.period == r.period && rsrc.version >= r.version { // 460 461 return nil, NewError(ErrInvalidValue, "A former update in this period is already known to exist") 462 } 463 464 chunk, err := r.toChunk() // 465 if err != nil { 466 return nil, err 467 } 468 469 // 470 h.chunkStore.Put(ctx, chunk) 471 log.Trace("resource update", "updateAddr", r.updateAddr, "lastperiod", r.period, "version", r.version, "data", chunk.SData, "multihash", r.multihash) 472 473 // 474 if rsrc != nil && (r.period > rsrc.period || (rsrc.period == r.period && r.version > rsrc.version)) { 475 rsrc.period = r.period 476 rsrc.version = r.version 477 rsrc.data = make([]byte, len(r.data)) 478 rsrc.updated = time.Now() 479 rsrc.lastKey = r.updateAddr 480 rsrc.multihash = r.multihash 481 copy(rsrc.data, r.data) 482 rsrc.Reader = bytes.NewReader(rsrc.data) 483 } 484 return r.updateAddr, nil 485 } 486 487 // 488 func (h *Handler) get(rootAddr storage.Address) *resource { 489 if len(rootAddr) < storage.KeyLength { 490 log.Warn("Handler.get with invalid rootAddr") 491 return nil 492 } 493 hashKey := *(*uint64)(unsafe.Pointer(&rootAddr[0])) 494 h.resourceLock.RLock() 495 defer h.resourceLock.RUnlock() 496 rsrc := h.resources[hashKey] 497 return rsrc 498 } 499 500 // 501 func (h *Handler) set(rootAddr storage.Address, rsrc *resource) { 502 if len(rootAddr) < storage.KeyLength { 503 log.Warn("Handler.set with invalid rootAddr") 504 return 505 } 506 hashKey := *(*uint64)(unsafe.Pointer(&rootAddr[0])) 507 h.resourceLock.Lock() 508 defer h.resourceLock.Unlock() 509 h.resources[hashKey] = rsrc 510 } 511 512 // 513 func (h *Handler) hasUpdate(rootAddr storage.Address, period uint32) bool { 514 rsrc := h.get(rootAddr) 515 return rsrc != nil && rsrc.period == period 516 } 517