github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/storage/mru/handler.go (about)

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