github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/feed/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 19:16:44</date>
    10  //</624450118912839680>
    11  
    12  
    13  //处理程序是源的API
    14  //它支持创建、更新、同步和检索源更新及其数据
    15  package feed
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"sync"
    22  
    23  	"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
    24  
    25  	"github.com/ethereum/go-ethereum/swarm/log"
    26  	"github.com/ethereum/go-ethereum/swarm/storage"
    27  )
    28  
    29  type Handler struct {
    30  	chunkStore *storage.NetStore
    31  	HashSize   int
    32  	cache      map[uint64]*cacheEntry
    33  	cacheLock  sync.RWMutex
    34  }
    35  
    36  //handlerParams将参数传递给处理程序构造函数newhandler
    37  //签名者和时间戳提供程序是必需的参数
    38  type HandlerParams struct {
    39  }
    40  
    41  //哈希池包含一个准备好的哈希器池
    42  var hashPool sync.Pool
    43  
    44  //init初始化包和哈希池
    45  func init() {
    46  	hashPool = sync.Pool{
    47  		New: func() interface{} {
    48  			return storage.MakeHashFunc(feedsHashAlgorithm)()
    49  		},
    50  	}
    51  }
    52  
    53  //NewHandler创建了一个新的Swarm Feeds API
    54  func NewHandler(params *HandlerParams) *Handler {
    55  	fh := &Handler{
    56  		cache: make(map[uint64]*cacheEntry),
    57  	}
    58  
    59  	for i := 0; i < hasherCount; i++ {
    60  		hashfunc := storage.MakeHashFunc(feedsHashAlgorithm)()
    61  		if fh.HashSize == 0 {
    62  			fh.HashSize = hashfunc.Size()
    63  		}
    64  		hashPool.Put(hashfunc)
    65  	}
    66  
    67  	return fh
    68  }
    69  
    70  //setstore为swarm feeds api设置存储后端
    71  func (h *Handler) SetStore(store *storage.NetStore) {
    72  	h.chunkStore = store
    73  }
    74  
    75  //validate是块验证方法
    76  //如果它看起来像一个提要更新,那么块地址将根据更新签名的useraddr进行检查。
    77  //它实现了storage.chunkvalidator接口
    78  func (h *Handler) Validate(chunk storage.Chunk) bool {
    79  	if len(chunk.Data()) < minimumSignedUpdateLength {
    80  		return false
    81  	}
    82  
    83  //检查它是否是格式正确的更新块
    84  //所尝试的源的有效签名和所有权证明
    85  //更新
    86  
    87  //首先,反序列化块
    88  	var r Request
    89  	if err := r.fromChunk(chunk); err != nil {
    90  		log.Debug("Invalid feed update chunk", "addr", chunk.Address(), "err", err)
    91  		return false
    92  	}
    93  
    94  //验证签名,并且签名者实际上拥有源
    95  //如果失败,则表示签名无效,数据已损坏。
    96  //或者有人试图更新其他人的订阅源。
    97  	if err := r.Verify(); err != nil {
    98  		log.Debug("Invalid feed update signature", "err", err)
    99  		return false
   100  	}
   101  
   102  	return true
   103  }
   104  
   105  //getContent检索源的上次同步更新的数据负载
   106  func (h *Handler) GetContent(feed *Feed) (storage.Address, []byte, error) {
   107  	if feed == nil {
   108  		return nil, nil, NewError(ErrInvalidValue, "feed is nil")
   109  	}
   110  	feedUpdate := h.get(feed)
   111  	if feedUpdate == nil {
   112  		return nil, nil, NewError(ErrNotFound, "feed update not cached")
   113  	}
   114  	return feedUpdate.lastKey, feedUpdate.data, nil
   115  }
   116  
   117  //NewRequest准备一个请求结构,其中包含
   118  //只需添加所需数据并签名即可。
   119  //然后可以对生成的结构进行签名并将其传递给handler.update以进行验证并发送
   120  func (h *Handler) NewRequest(ctx context.Context, feed *Feed) (request *Request, err error) {
   121  	if feed == nil {
   122  		return nil, NewError(ErrInvalidValue, "feed cannot be nil")
   123  	}
   124  
   125  	now := TimestampProvider.Now().Time
   126  	request = new(Request)
   127  	request.Header.Version = ProtocolVersion
   128  
   129  	query := NewQueryLatest(feed, lookup.NoClue)
   130  
   131  	feedUpdate, err := h.Lookup(ctx, query)
   132  	if err != nil {
   133  		if err.(*Error).code != ErrNotFound {
   134  			return nil, err
   135  		}
   136  //找不到更新意味着存在网络错误
   137  //或者订阅源确实没有更新
   138  	}
   139  
   140  	request.Feed = *feed
   141  
   142  //如果我们已经有了更新,那么找到下一个时代
   143  	if feedUpdate != nil {
   144  		request.Epoch = lookup.GetNextEpoch(feedUpdate.Epoch, now)
   145  	} else {
   146  		request.Epoch = lookup.GetFirstEpoch(now)
   147  	}
   148  
   149  	return request, nil
   150  }
   151  
   152  //查找检索特定或最新的源更新
   153  //根据“query”的配置,查找的工作方式不同
   154  //请参阅“query”文档和帮助器函数:
   155  //`newquerylatest`和'newquery`
   156  func (h *Handler) Lookup(ctx context.Context, query *Query) (*cacheEntry, error) {
   157  
   158  	timeLimit := query.TimeLimit
   159  if timeLimit == 0 { //如果时间限制设置为零,则用户希望获取最新更新
   160  		timeLimit = TimestampProvider.Now().Time
   161  	}
   162  
   163  if query.Hint == lookup.NoClue { //尝试使用我们的缓存
   164  		entry := h.get(&query.Feed)
   165  if entry != nil && entry.Epoch.Time <= timeLimit { //避免不良提示
   166  			query.Hint = entry.Epoch
   167  		}
   168  	}
   169  
   170  //没有商店我们找不到任何东西
   171  	if h.chunkStore == nil {
   172  		return nil, NewError(ErrInit, "Call Handler.SetStore() before performing lookups")
   173  	}
   174  
   175  	var id ID
   176  	id.Feed = query.Feed
   177  	var readCount int
   178  
   179  //调用查找引擎。
   180  //每次查找算法需要猜测时都将调用回调
   181  	requestPtr, err := lookup.Lookup(timeLimit, query.Hint, func(epoch lookup.Epoch, now uint64) (interface{}, error) {
   182  		readCount++
   183  		id.Epoch = epoch
   184  		ctx, cancel := context.WithTimeout(ctx, defaultRetrieveTimeout)
   185  		defer cancel()
   186  
   187  		chunk, err := h.chunkStore.Get(ctx, id.Addr())
   188  if err != nil { //TODO:未找到块以外的灾难性错误
   189  			return nil, nil
   190  		}
   191  
   192  		var request Request
   193  		if err := request.fromChunk(chunk); err != nil {
   194  			return nil, nil
   195  		}
   196  		if request.Time <= timeLimit {
   197  			return &request, nil
   198  		}
   199  		return nil, nil
   200  	})
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  
   205  	log.Info(fmt.Sprintf("Feed lookup finished in %d lookups", readCount))
   206  
   207  	request, _ := requestPtr.(*Request)
   208  	if request == nil {
   209  		return nil, NewError(ErrNotFound, "no feed updates found")
   210  	}
   211  	return h.updateCache(request)
   212  
   213  }
   214  
   215  //使用指定内容更新源更新缓存
   216  func (h *Handler) updateCache(request *Request) (*cacheEntry, error) {
   217  
   218  	updateAddr := request.Addr()
   219  	log.Trace("feed cache update", "topic", request.Topic.Hex(), "updateaddr", updateAddr, "epoch time", request.Epoch.Time, "epoch level", request.Epoch.Level)
   220  
   221  	feedUpdate := h.get(&request.Feed)
   222  	if feedUpdate == nil {
   223  		feedUpdate = &cacheEntry{}
   224  		h.set(&request.Feed, feedUpdate)
   225  	}
   226  
   227  //更新我们的RSRCS入口地图
   228  	feedUpdate.lastKey = updateAddr
   229  	feedUpdate.Update = request.Update
   230  	feedUpdate.Reader = bytes.NewReader(feedUpdate.data)
   231  	return feedUpdate, nil
   232  }
   233  
   234  //更新发布源更新
   235  //请注意,提要更新不能跨越块,因此具有最大净长度4096,包括更新头数据和签名。
   236  //这将导致最大负载为“maxupdatedatalength”(有关详细信息,请检查update.go)
   237  //如果区块负载的总长度将超过此限制,则返回错误。
   238  //更新只能检查调用方是否试图覆盖最新的已知版本,否则它只会将更新
   239  //在网络上。
   240  func (h *Handler) Update(ctx context.Context, r *Request) (updateAddr storage.Address, err error) {
   241  
   242  //没有商店我们无法更新任何内容
   243  	if h.chunkStore == nil {
   244  		return nil, NewError(ErrInit, "Call Handler.SetStore() before updating")
   245  	}
   246  
   247  	feedUpdate := h.get(&r.Feed)
   248  if feedUpdate != nil && feedUpdate.Epoch.Equals(r.Epoch) { //这是我们唯一能确定的便宜支票
   249  		return nil, NewError(ErrInvalidValue, "A former update in this epoch is already known to exist")
   250  	}
   251  
   252  chunk, err := r.toChunk() //将更新序列化为块。如果数据太大则失败
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  
   257  //发送块
   258  	h.chunkStore.Put(ctx, chunk)
   259  	log.Trace("feed update", "updateAddr", r.idAddr, "epoch time", r.Epoch.Time, "epoch level", r.Epoch.Level, "data", chunk.Data())
   260  //更新我们的feed更新映射缓存条目,如果新的更新比我们现有的更新旧,如果我们有。
   261  	if feedUpdate != nil && r.Epoch.After(feedUpdate.Epoch) {
   262  		feedUpdate.Epoch = r.Epoch
   263  		feedUpdate.data = make([]byte, len(r.data))
   264  		feedUpdate.lastKey = r.idAddr
   265  		copy(feedUpdate.data, r.data)
   266  		feedUpdate.Reader = bytes.NewReader(feedUpdate.data)
   267  	}
   268  
   269  	return r.idAddr, nil
   270  }
   271  
   272  //检索给定名称哈希的源更新缓存值
   273  func (h *Handler) get(feed *Feed) *cacheEntry {
   274  	mapKey := feed.mapKey()
   275  	h.cacheLock.RLock()
   276  	defer h.cacheLock.RUnlock()
   277  	feedUpdate := h.cache[mapKey]
   278  	return feedUpdate
   279  }
   280  
   281  //设置给定源的源更新缓存值
   282  func (h *Handler) set(feed *Feed, feedUpdate *cacheEntry) {
   283  	mapKey := feed.mapKey()
   284  	h.cacheLock.Lock()
   285  	defer h.cacheLock.Unlock()
   286  	h.cache[mapKey] = feedUpdate
   287  }
   288