@@ -29,9 +29,9 @@ type resource struct {
2929 name string
3030 ensName common.Hash
3131 startBlock uint64
32- lastBlock uint64
32+ lastPeriod uint32
3333 frequency uint64
34- version uint64
34+ version uint32
3535 data []byte
3636 updated time.Time
3737}
@@ -102,7 +102,7 @@ type ResourceHandler struct {
102102 ethapi * rpc.Client
103103 resources map [string ]* resource
104104 hashLock sync.Mutex
105- resourceLock sync.Mutex
105+ resourceLock sync.RWMutex
106106 hasher SwarmHash
107107 privKey * ecdsa.PrivateKey
108108 maxChunkData int64
@@ -168,7 +168,7 @@ func NewResource(name string, startBlock uint64, frequency uint64) (*resource, e
168168 }, nil
169169}
170170
171- // Creates a new root entry for a resource update identified by `name` with the specified `frequency`.
171+ // Creates a new root entry for a mutable resource identified by `name` with the specified `frequency`.
172172//
173173// The start block of the resource update will be the actual current block height of the connected network.
174174func (self * ResourceHandler ) NewResource (name string , frequency uint64 ) (* resource , error ) {
@@ -202,15 +202,15 @@ func (self *ResourceHandler) NewResource(name string, frequency uint64) (*resour
202202 self .Put (chunk )
203203 log .Debug ("new resource" , "name" , validname , "key" , ensName , "startBlock" , currentblock , "frequency" , frequency )
204204
205- self .resourceLock .Lock ()
206- defer self .resourceLock .Unlock ()
207- self .resources [name ] = & resource {
205+ rsrc := & resource {
208206 name : validname ,
209207 ensName : ensName ,
210208 startBlock : currentblock ,
211209 frequency : frequency ,
212210 updated : time .Now (),
213211 }
212+ self .setResource (name , rsrc )
213+
214214 return self .resources [name ], nil
215215}
216216
@@ -258,12 +258,12 @@ func (self *ResourceHandler) SetResource(rsrc *resource, allowOverwrite bool) er
258258// root chunk.
259259// It is the callers responsibility to make sure that this chunk exists (if the resource
260260// update root data was retrieved externally, it typically doesn't)
261- func (self * ResourceHandler ) LookupVersion (name string , nextblock uint64 , version uint64 , refresh bool ) (* resource , error ) {
261+ func (self * ResourceHandler ) LookupVersion (name string , period uint32 , version uint32 , refresh bool ) (* resource , error ) {
262262 rsrc , err := self .loadResource (name , refresh )
263263 if err != nil {
264264 return nil , err
265265 }
266- return self .lookup (rsrc , name , nextblock , version , refresh )
266+ return self .lookup (rsrc , name , period , version , refresh )
267267}
268268
269269// Retrieves the latest version of the resource update identified by `name`
@@ -274,12 +274,12 @@ func (self *ResourceHandler) LookupVersion(name string, nextblock uint64, versio
274274// and returned.
275275//
276276// See also (*ResourceHandler).LookupVersion
277- func (self * ResourceHandler ) LookupHistorical (name string , nextblock uint64 , refresh bool ) (* resource , error ) {
277+ func (self * ResourceHandler ) LookupHistorical (name string , period uint32 , refresh bool ) (* resource , error ) {
278278 rsrc , err := self .loadResource (name , refresh )
279279 if err != nil {
280280 return nil , err
281281 }
282- return self .lookup (rsrc , name , nextblock , 0 , refresh )
282+ return self .lookup (rsrc , name , period , 0 , refresh )
283283}
284284
285285// Retrieves the latest version of the resource update identified by `name`
@@ -303,15 +303,15 @@ func (self *ResourceHandler) LookupLatest(name string, refresh bool) (*resource,
303303 if err != nil {
304304 return nil , err
305305 }
306- nextblock := getNextBlock (rsrc .startBlock , currentblock , rsrc .frequency )
307- return self .lookup (rsrc , name , nextblock , 0 , refresh )
306+ nextperiod := getNextPeriod (rsrc .startBlock , currentblock , rsrc .frequency )
307+ return self .lookup (rsrc , name , nextperiod , 0 , refresh )
308308}
309309
310310// base code for public lookup methods
311- func (self * ResourceHandler ) lookup (rsrc * resource , name string , nextblock uint64 , version uint64 , refresh bool ) (* resource , error ) {
311+ func (self * ResourceHandler ) lookup (rsrc * resource , name string , period uint32 , version uint32 , refresh bool ) (* resource , error ) {
312312
313- if nextblock == 0 {
314- return nil , fmt .Errorf ("blocknumber must be >0" )
313+ if period == 0 {
314+ return nil , fmt .Errorf ("period must be >0" )
315315 }
316316
317317 // start from the last possible block period, and iterate previous ones until we find a match
@@ -323,29 +323,29 @@ func (self *ResourceHandler) lookup(rsrc *resource, name string, nextblock uint6
323323 version = 1
324324 }
325325
326- for nextblock > rsrc . startBlock {
327- key := self .resourceHash (rsrc .ensName , nextblock , version )
326+ for period > 0 {
327+ key := self .resourceHash (rsrc .ensName , period , version )
328328 chunk , err := self .Get (key )
329329 if err == nil {
330330 if specificversion {
331- return self .updateResourceIndex (rsrc , chunk , nextblock , version , & name )
331+ return self .updateResourceIndex (rsrc , chunk , & name )
332332 }
333333 // check if we have versions > 1. If a version fails, the previous version is used and returned.
334- log .Trace ("rsrc update version 1 found, checking for version updates" , "nextblock " , nextblock , "key" , key )
334+ log .Trace ("rsrc update version 1 found, checking for version updates" , "period " , period , "key" , key )
335335 for {
336336 newversion := version + 1
337- key := self .resourceHash (rsrc .ensName , nextblock , newversion )
337+ key := self .resourceHash (rsrc .ensName , period , newversion )
338338 newchunk , err := self .Get (key )
339339 if err != nil {
340- return self .updateResourceIndex (rsrc , chunk , nextblock , version , & name )
340+ return self .updateResourceIndex (rsrc , chunk , & name )
341341 }
342- log .Trace ("version update found, checking next" , "version" , version , "block " , nextblock , "key" , key )
342+ log .Trace ("version update found, checking next" , "version" , version , "period " , period , "key" , key )
343343 chunk = newchunk
344344 version = newversion
345345 }
346346 }
347- log .Trace ("rsrc update not found, checking previous period" , "block " , nextblock , "key" , key )
348- nextblock -= rsrc . frequency
347+ log .Trace ("rsrc update not found, checking previous period" , "period " , period , "key" , key )
348+ period --
349349 }
350350 return nil , fmt .Errorf ("no updates found" )
351351}
@@ -355,12 +355,9 @@ func (self *ResourceHandler) loadResource(name string, refresh bool) (*resource,
355355 // if the resource is not known to this session we must load it
356356 // if refresh is set, we force load
357357
358- rsrc := & resource {}
359-
360- self .resourceLock .Lock ()
361- _ , ok := self .resources [name ]
362- self .resourceLock .Unlock ()
363- if ! ok || refresh {
358+ rsrc := self .getResource (name )
359+ if rsrc == nil || refresh {
360+ rsrc = & resource {}
364361 // make sure our ens identifier is idna safe
365362 validname , err := idna .ToASCII (name )
366363 if err != nil {
@@ -397,7 +394,7 @@ func (self *ResourceHandler) loadResource(name string, refresh bool) (*resource,
397394}
398395
399396// update mutable resource index map with specified content
400- func (self * ResourceHandler ) updateResourceIndex (rsrc * resource , chunk * Chunk , nextblock uint64 , version uint64 , indexname * string ) (* resource , error ) {
397+ func (self * ResourceHandler ) updateResourceIndex (rsrc * resource , chunk * Chunk , indexname * string ) (* resource , error ) {
401398
402399 // rsrc update data chunks are total hacks
403400 // and have no size prefix :D
@@ -407,18 +404,36 @@ func (self *ResourceHandler) updateResourceIndex(rsrc *resource, chunk *Chunk, n
407404 }
408405
409406 // update our rsrcs entry map
410- rsrc .lastBlock = nextblock
407+ period , version , _ , data , err := parseUpdate (chunk .SData [signatureLength :])
408+ rsrc .lastPeriod = period
411409 rsrc .version = version
412- rsrc .data = make ([]byte , len (chunk .SData )- signatureLength )
413410 rsrc .updated = time .Now ()
414- copy (rsrc .data , chunk .SData [signatureLength :])
415- log .Debug ("Resource synced" , "name" , rsrc .name , "key" , chunk .Key , "block" , nextblock , "version" , version )
416- self .resourceLock .Lock ()
417- self .resources [* indexname ] = rsrc
418- self .resourceLock .Unlock ()
411+ rsrc .data = make ([]byte , len (data ))
412+ copy (rsrc .data , data )
413+ log .Debug ("Resource synced" , "name" , rsrc .name , "key" , chunk .Key , "period" , rsrc .lastPeriod , "version" , rsrc .version )
414+ self .setResource (* indexname , rsrc )
419415 return rsrc , nil
420416}
421417
418+ func parseUpdate (blob []byte ) (period uint32 , version uint32 , ensname []byte , data []byte , err error ) {
419+ headerlength := binary .LittleEndian .Uint16 (blob [:2 ])
420+ if int (headerlength + 2 ) > len (blob ) {
421+ return 0 , 0 , nil , nil , fmt .Errorf ("Reported header length %d longer than actual data length %d" , headerlength , len (blob ))
422+ }
423+ cursor := 2
424+ period = binary .LittleEndian .Uint32 (blob [cursor : cursor + 4 ])
425+ cursor += 4
426+ version = binary .LittleEndian .Uint32 (blob [cursor : cursor + 4 ])
427+ cursor += 4
428+ namelength := int (headerlength ) - cursor + 2
429+ ensname = make ([]byte , namelength )
430+ copy (ensname , blob [cursor :])
431+ cursor += namelength
432+ data = make ([]byte , len (blob )- cursor )
433+ copy (data , blob [cursor :])
434+ return
435+ }
436+
422437// Adds an actual data update
423438//
424439// Uses the data currently loaded in the resources map entry.
@@ -447,28 +462,48 @@ func (self *ResourceHandler) Update(name string, data []byte) (Key, error) {
447462 if err != nil {
448463 return nil , err
449464 }
450- nextblock := getNextBlock (resource .startBlock , currentblock , resource .frequency )
465+ nextperiod := getNextPeriod (resource .startBlock , currentblock , resource .frequency )
451466
452467 // if we already have an update for this block then increment version
453- var version uint64
454- if nextblock == resource . lastBlock {
468+ var version uint32
469+ if self . hasUpdate ( name , nextperiod ) {
455470 version = resource .version
456471 }
457472 version ++
458473
474+ // prepend version and period to allow reverse lookups
475+ // data header length does NOT include the header length prefix bytes themselves
476+ headerlength := uint16 (len (resource .ensName ) + 4 + 4 )
477+ fulldata := make ([]byte , int (headerlength )+ 2 + len (data ))
478+
479+ cursor := 0
480+ binary .LittleEndian .PutUint16 (fulldata , headerlength )
481+ cursor += 2
482+
483+ binary .LittleEndian .PutUint32 (fulldata [cursor :], nextperiod )
484+ cursor += 4
485+
486+ binary .LittleEndian .PutUint32 (fulldata [cursor :], version )
487+ cursor += 4
488+
489+ copy (fulldata [cursor :], resource .ensName [:])
490+ cursor += len (resource .ensName )
491+
492+ copy (fulldata [cursor :], data )
493+
459494 // create the update chunk and send it
460- key := self .resourceHash (resource .ensName , nextblock , version )
495+ key := self .resourceHash (resource .ensName , nextperiod , version )
461496 chunk := NewChunk (key , nil )
462- chunk .SData , err = self .signContent (data )
497+ chunk .SData , err = self .signContent (fulldata )
463498 if err != nil {
464499 return nil , err
465500 }
466- chunk .Size = int64 (len (data ))
501+ chunk .Size = int64 (len (fulldata ))
467502 self .Put (chunk )
468- log .Trace ("resource update" , "name" , resource .name , "key" , key , "currentblock" , currentblock , "lastBlock " , nextblock , "version" , version )
503+ log .Trace ("resource update" , "name" , resource .name , "key" , key , "currentblock" , currentblock , "lastperiod " , nextperiod , "version" , version , "data" , chunk . SData )
469504
470505 // update our resources map entry and return the new key
471- resource .lastBlock = nextblock
506+ resource .lastPeriod = nextperiod
472507 resource .version = version
473508 resource .data = make ([]byte , len (data ))
474509 copy (resource .data , data )
@@ -494,20 +529,37 @@ func (self *ResourceHandler) getBlock() (uint64, error) {
494529 return strconv .ParseUint (currentblock , 10 , 64 )
495530}
496531
497- func (self * ResourceHandler ) resourceHash (namehash common.Hash , blockheight uint64 , version uint64 ) Key {
498- // format is: hash(namehash|blockheight|version)
532+ func (self * ResourceHandler ) BlockToPeriod (name string , blocknumber uint64 ) uint32 {
533+ return getNextPeriod (self .resources [name ].startBlock , blocknumber , self .resources [name ].frequency )
534+ }
535+
536+ func (self * ResourceHandler ) PeriodToBlock (name string , period uint32 ) uint64 {
537+ return self .resources [name ].startBlock + (uint64 (period ) * self .resources [name ].frequency )
538+ }
539+
540+ func (self * ResourceHandler ) getResource (name string ) * resource {
541+ self .resourceLock .RLock ()
542+ defer self .resourceLock .RUnlock ()
543+ rsrc := self .resources [name ]
544+ return rsrc
545+ }
546+
547+ func (self * ResourceHandler ) setResource (name string , rsrc * resource ) {
548+ self .resourceLock .Lock ()
549+ defer self .resourceLock .Unlock ()
550+ self .resources [name ] = rsrc
551+ }
552+
553+ func (self * ResourceHandler ) resourceHash (namehash common.Hash , period uint32 , version uint32 ) Key {
554+ // format is: hash(namehash|period|version)
499555 self .hashLock .Lock ()
500556 defer self .hashLock .Unlock ()
501557 self .hasher .Reset ()
502558 self .hasher .Write (namehash [:])
503- b := make ([]byte , 8 )
504- c := binary .PutUvarint (b , blockheight )
559+ b := make ([]byte , 4 )
560+ binary .LittleEndian . PutUint32 (b , period )
505561 self .hasher .Write (b )
506- // PutUvarint only overwrites first c bytes
507- for i := 0 ; i < c ; i ++ {
508- b [i ] = 0
509- }
510- c = binary .PutUvarint (b , version )
562+ binary .LittleEndian .PutUint32 (b , version )
511563 self .hasher .Write (b )
512564 return self .hasher .Sum (nil )
513565}
@@ -554,6 +606,13 @@ func (self *ResourceHandler) verifyContent(chunkdata []byte) error {
554606 return nil
555607}
556608
609+ func (self * ResourceHandler ) hasUpdate (name string , period uint32 ) bool {
610+ if self .resources [name ].lastPeriod == period {
611+ return true
612+ }
613+ return false
614+ }
615+
557616type resourceChunkStore struct {
558617 localStore ChunkStore
559618 netStore ChunkStore
@@ -596,8 +655,8 @@ func (r *resourceChunkStore) Close() {
596655 r .localStore .Close ()
597656}
598657
599- func getNextBlock (start uint64 , current uint64 , frequency uint64 ) uint64 {
658+ func getNextPeriod (start uint64 , current uint64 , frequency uint64 ) uint32 {
600659 blockdiff := current - start
601- periods := ( blockdiff / frequency ) + 1
602- return start + ( frequency * periods )
660+ period := blockdiff / frequency
661+ return uint32 ( period + 1 )
603662}
0 commit comments