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