github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/filters/api.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  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package filters
    26  
    27  import (
    28  	"context"
    29  	"encoding/json"
    30  	"errors"
    31  	"fmt"
    32  	"math/big"
    33  	"sync"
    34  	"time"
    35  
    36  	ethereum "github.com/ethereum/go-ethereum"
    37  	"github.com/ethereum/go-ethereum/common"
    38  	"github.com/ethereum/go-ethereum/common/hexutil"
    39  	"github.com/ethereum/go-ethereum/core/types"
    40  	"github.com/ethereum/go-ethereum/ethdb"
    41  	"github.com/ethereum/go-ethereum/event"
    42  	"github.com/ethereum/go-ethereum/rpc"
    43  )
    44  
    45  var (
    46  deadline = 5 * time.Minute //如果在截止日期内未对某个筛选器进行轮询,则认为该筛选器处于非活动状态
    47  )
    48  
    49  //filter是一个在filter类型上保存元信息的helper结构
    50  //以及事件系统中的关联订阅。
    51  type filter struct {
    52  	typ      Type
    53  deadline *time.Timer //截止时间触发时,筛选器不活动
    54  	hashes   []common.Hash
    55  	crit     FilterCriteria
    56  	logs     []*types.Log
    57  s        *Subscription //事件系统中的关联订阅
    58  }
    59  
    60  //publicfilterapi提供创建和管理过滤器的支持。这将允许外部客户端检索
    61  //与以太坊协议相关的信息,如ALS块、事务和日志。
    62  type PublicFilterAPI struct {
    63  	backend   Backend
    64  	mux       *event.TypeMux
    65  	quit      chan struct{}
    66  	chainDb   ethdb.Database
    67  	events    *EventSystem
    68  	filtersMu sync.Mutex
    69  	filters   map[rpc.ID]*filter
    70  }
    71  
    72  //new publicfilterapi返回新的publicfilterapi实例。
    73  func NewPublicFilterAPI(backend Backend, lightMode bool) *PublicFilterAPI {
    74  	api := &PublicFilterAPI{
    75  		backend: backend,
    76  		mux:     backend.EventMux(),
    77  		chainDb: backend.ChainDb(),
    78  		events:  NewEventSystem(backend.EventMux(), backend, lightMode),
    79  		filters: make(map[rpc.ID]*filter),
    80  	}
    81  	go api.timeoutLoop()
    82  
    83  	return api
    84  }
    85  
    86  //TimeoutLoop每5分钟运行一次,并删除最近未使用的筛选器。
    87  //TT在创建API时启动。
    88  func (api *PublicFilterAPI) timeoutLoop() {
    89  	ticker := time.NewTicker(5 * time.Minute)
    90  	for {
    91  		<-ticker.C
    92  		api.filtersMu.Lock()
    93  		for id, f := range api.filters {
    94  			select {
    95  			case <-f.deadline.C:
    96  				f.s.Unsubscribe()
    97  				delete(api.filters, id)
    98  			default:
    99  				continue
   100  			}
   101  		}
   102  		api.filtersMu.Unlock()
   103  	}
   104  }
   105  
   106  //NewPendingtTransactionFilter创建一个筛选器,用于获取挂起的事务哈希
   107  //当事务进入挂起状态时。
   108  //
   109  //它是筛选器包的一部分,因为此筛选器可以通过
   110  //“eth”getfilterchanges“轮询方法,也用于日志筛选器。
   111  //
   112  //https://github.com/ethereum/wiki/wiki/json-rpc_eth_newpendingtransactionfilter
   113  func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID {
   114  	var (
   115  		pendingTxs   = make(chan []common.Hash)
   116  		pendingTxSub = api.events.SubscribePendingTxs(pendingTxs)
   117  	)
   118  
   119  	api.filtersMu.Lock()
   120  	api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(deadline), hashes: make([]common.Hash, 0), s: pendingTxSub}
   121  	api.filtersMu.Unlock()
   122  
   123  	go func() {
   124  		for {
   125  			select {
   126  			case ph := <-pendingTxs:
   127  				api.filtersMu.Lock()
   128  				if f, found := api.filters[pendingTxSub.ID]; found {
   129  					f.hashes = append(f.hashes, ph...)
   130  				}
   131  				api.filtersMu.Unlock()
   132  			case <-pendingTxSub.Err():
   133  				api.filtersMu.Lock()
   134  				delete(api.filters, pendingTxSub.ID)
   135  				api.filtersMu.Unlock()
   136  				return
   137  			}
   138  		}
   139  	}()
   140  
   141  	return pendingTxSub.ID
   142  }
   143  
   144  //NewPendingtTransactions创建每次事务触发的订阅
   145  //进入事务池,并从该节点管理的事务之一签名。
   146  func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Subscription, error) {
   147  	notifier, supported := rpc.NotifierFromContext(ctx)
   148  	if !supported {
   149  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   150  	}
   151  
   152  	rpcSub := notifier.CreateSubscription()
   153  
   154  	go func() {
   155  		txHashes := make(chan []common.Hash, 128)
   156  		pendingTxSub := api.events.SubscribePendingTxs(txHashes)
   157  
   158  		for {
   159  			select {
   160  			case hashes := <-txHashes:
   161  //要保持原始行为,请在一个通知中发送单个Tx哈希。
   162  //TODO(RJL493456442)在一个通知中发送一批Tx哈希
   163  				for _, h := range hashes {
   164  					notifier.Notify(rpcSub.ID, h)
   165  				}
   166  			case <-rpcSub.Err():
   167  				pendingTxSub.Unsubscribe()
   168  				return
   169  			case <-notifier.Closed():
   170  				pendingTxSub.Unsubscribe()
   171  				return
   172  			}
   173  		}
   174  	}()
   175  
   176  	return rpcSub, nil
   177  }
   178  
   179  //newblockfilter创建一个过滤器,用于获取导入到链中的块。
   180  //它是筛选包的一部分,因为轮询与ethgetfilterchanges一起进行。
   181  //
   182  //https://github.com/ethereum/wiki/wiki/json-rpc eth newblockfilter
   183  func (api *PublicFilterAPI) NewBlockFilter() rpc.ID {
   184  	var (
   185  		headers   = make(chan *types.Header)
   186  		headerSub = api.events.SubscribeNewHeads(headers)
   187  	)
   188  
   189  	api.filtersMu.Lock()
   190  	api.filters[headerSub.ID] = &filter{typ: BlocksSubscription, deadline: time.NewTimer(deadline), hashes: make([]common.Hash, 0), s: headerSub}
   191  	api.filtersMu.Unlock()
   192  
   193  	go func() {
   194  		for {
   195  			select {
   196  			case h := <-headers:
   197  				api.filtersMu.Lock()
   198  				if f, found := api.filters[headerSub.ID]; found {
   199  					f.hashes = append(f.hashes, h.Hash())
   200  				}
   201  				api.filtersMu.Unlock()
   202  			case <-headerSub.Err():
   203  				api.filtersMu.Lock()
   204  				delete(api.filters, headerSub.ID)
   205  				api.filtersMu.Unlock()
   206  				return
   207  			}
   208  		}
   209  	}()
   210  
   211  	return headerSub.ID
   212  }
   213  
   214  //每当新(header)块附加到链时,newheads都会发送通知。
   215  func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) {
   216  	notifier, supported := rpc.NotifierFromContext(ctx)
   217  	if !supported {
   218  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   219  	}
   220  
   221  	rpcSub := notifier.CreateSubscription()
   222  
   223  	go func() {
   224  		headers := make(chan *types.Header)
   225  		headersSub := api.events.SubscribeNewHeads(headers)
   226  
   227  		for {
   228  			select {
   229  			case h := <-headers:
   230  				notifier.Notify(rpcSub.ID, h)
   231  			case <-rpcSub.Err():
   232  				headersSub.Unsubscribe()
   233  				return
   234  			case <-notifier.Closed():
   235  				headersSub.Unsubscribe()
   236  				return
   237  			}
   238  		}
   239  	}()
   240  
   241  	return rpcSub, nil
   242  }
   243  
   244  //日志创建一个订阅,该订阅为所有符合给定筛选条件的新日志激发。
   245  func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subscription, error) {
   246  	notifier, supported := rpc.NotifierFromContext(ctx)
   247  	if !supported {
   248  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   249  	}
   250  
   251  	var (
   252  		rpcSub      = notifier.CreateSubscription()
   253  		matchedLogs = make(chan []*types.Log)
   254  	)
   255  
   256  	logsSub, err := api.events.SubscribeLogs(ethereum.FilterQuery(crit), matchedLogs)
   257  	if err != nil {
   258  		return nil, err
   259  	}
   260  
   261  	go func() {
   262  
   263  		for {
   264  			select {
   265  			case logs := <-matchedLogs:
   266  				for _, log := range logs {
   267  					notifier.Notify(rpcSub.ID, &log)
   268  				}
   269  case <-rpcSub.Err(): //客户端发送取消订阅请求
   270  				logsSub.Unsubscribe()
   271  				return
   272  case <-notifier.Closed(): //连接已断开
   273  				logsSub.Unsubscribe()
   274  				return
   275  			}
   276  		}
   277  	}()
   278  
   279  	return rpcSub, nil
   280  }
   281  
   282  //FilterCriteria表示创建新筛选器的请求。
   283  //与ethereum.filterquery相同,但使用unmashaljson()方法。
   284  type FilterCriteria ethereum.FilterQuery
   285  
   286  //new filter创建新的筛选器并返回筛选器ID。它可以是
   287  //用于在状态更改时检索日志。此方法不能
   288  //用于获取已存储在状态中的日志。
   289  //
   290  //“从”和“到”块的默认条件为“最新”。
   291  //使用“最新”作为块号将返回已开采块的日志。
   292  //使用“挂起”作为块号返回尚未挖掘(挂起)块的日志。
   293  //如果日志被删除(链ReRoG),则返回以前返回的日志。
   294  //再次,但将移除的属性设置为true。
   295  //
   296  //如果“fromblock”>toblock,则返回错误。
   297  //
   298  //https://github.com/ethereum/wiki/wiki/json-rpc_eth_newfilter
   299  func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
   300  	logs := make(chan []*types.Log)
   301  	logsSub, err := api.events.SubscribeLogs(ethereum.FilterQuery(crit), logs)
   302  	if err != nil {
   303  		return rpc.ID(""), err
   304  	}
   305  
   306  	api.filtersMu.Lock()
   307  	api.filters[logsSub.ID] = &filter{typ: LogsSubscription, crit: crit, deadline: time.NewTimer(deadline), logs: make([]*types.Log, 0), s: logsSub}
   308  	api.filtersMu.Unlock()
   309  
   310  	go func() {
   311  		for {
   312  			select {
   313  			case l := <-logs:
   314  				api.filtersMu.Lock()
   315  				if f, found := api.filters[logsSub.ID]; found {
   316  					f.logs = append(f.logs, l...)
   317  				}
   318  				api.filtersMu.Unlock()
   319  			case <-logsSub.Err():
   320  				api.filtersMu.Lock()
   321  				delete(api.filters, logsSub.ID)
   322  				api.filtersMu.Unlock()
   323  				return
   324  			}
   325  		}
   326  	}()
   327  
   328  	return logsSub.ID, nil
   329  }
   330  
   331  //GetLogs返回与存储在状态中的给定参数匹配的日志。
   332  //
   333  //https://github.com/ethereum/wiki/wiki/json-rpc eth getlogs
   334  func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) {
   335  	var filter *Filter
   336  	if crit.BlockHash != nil {
   337  //请求块筛选器,构造一个单镜头筛选器
   338  		filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics)
   339  	} else {
   340  //将RPC块编号转换为内部表示形式
   341  		begin := rpc.LatestBlockNumber.Int64()
   342  		if crit.FromBlock != nil {
   343  			begin = crit.FromBlock.Int64()
   344  		}
   345  		end := rpc.LatestBlockNumber.Int64()
   346  		if crit.ToBlock != nil {
   347  			end = crit.ToBlock.Int64()
   348  		}
   349  //构造范围过滤器
   350  		filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics)
   351  	}
   352  //运行过滤器并返回所有日志
   353  	logs, err := filter.Logs(ctx)
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  	return returnLogs(logs), err
   358  }
   359  
   360  //uninstallfilter删除具有给定筛选器ID的筛选器。
   361  //
   362  //https://github.com/ethereum/wiki/wiki/json-rpc_eth_卸载过滤器
   363  func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool {
   364  	api.filtersMu.Lock()
   365  	f, found := api.filters[id]
   366  	if found {
   367  		delete(api.filters, id)
   368  	}
   369  	api.filtersMu.Unlock()
   370  	if found {
   371  		f.s.Unsubscribe()
   372  	}
   373  
   374  	return found
   375  }
   376  
   377  //GetFilterLogs返回具有给定ID的筛选器的日志。
   378  //如果找不到筛选器,则返回一个空的日志数组。
   379  //
   380  //https://github.com/ethereum/wiki/wiki/json-rpc_eth_getfilterlogs
   381  func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Log, error) {
   382  	api.filtersMu.Lock()
   383  	f, found := api.filters[id]
   384  	api.filtersMu.Unlock()
   385  
   386  	if !found || f.typ != LogsSubscription {
   387  		return nil, fmt.Errorf("filter not found")
   388  	}
   389  
   390  	var filter *Filter
   391  	if f.crit.BlockHash != nil {
   392  //请求块筛选器,构造一个单镜头筛选器
   393  		filter = NewBlockFilter(api.backend, *f.crit.BlockHash, f.crit.Addresses, f.crit.Topics)
   394  	} else {
   395  //将RPC块编号转换为内部表示形式
   396  		begin := rpc.LatestBlockNumber.Int64()
   397  		if f.crit.FromBlock != nil {
   398  			begin = f.crit.FromBlock.Int64()
   399  		}
   400  		end := rpc.LatestBlockNumber.Int64()
   401  		if f.crit.ToBlock != nil {
   402  			end = f.crit.ToBlock.Int64()
   403  		}
   404  //构造范围过滤器
   405  		filter = NewRangeFilter(api.backend, begin, end, f.crit.Addresses, f.crit.Topics)
   406  	}
   407  //运行过滤器并返回所有日志
   408  	logs, err := filter.Logs(ctx)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  	return returnLogs(logs), nil
   413  }
   414  
   415  //GetFilterChanges返回具有给定ID的筛选器的日志,自
   416  //上次打电话的时候。这可以用于轮询。
   417  //
   418  //对于挂起的事务和块筛选器,结果是[]common.hash。
   419  //(挂起)日志筛选器返回[]日志。
   420  //
   421  //https://github.com/ethereum/wiki/wiki/json-rpc_eth_getfilterchanges
   422  func (api *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
   423  	api.filtersMu.Lock()
   424  	defer api.filtersMu.Unlock()
   425  
   426  	if f, found := api.filters[id]; found {
   427  		if !f.deadline.Stop() {
   428  //计时器已过期,但在超时循环中尚未删除筛选器
   429  //接收计时器值并重置计时器
   430  			<-f.deadline.C
   431  		}
   432  		f.deadline.Reset(deadline)
   433  
   434  		switch f.typ {
   435  		case PendingTransactionsSubscription, BlocksSubscription:
   436  			hashes := f.hashes
   437  			f.hashes = nil
   438  			return returnHashes(hashes), nil
   439  		case LogsSubscription:
   440  			logs := f.logs
   441  			f.logs = nil
   442  			return returnLogs(logs), nil
   443  		}
   444  	}
   445  
   446  	return []interface{}{}, fmt.Errorf("filter not found")
   447  }
   448  
   449  //ReturnHashes是一个助手,在给定哈希数组为零的情况下将返回空哈希数组,
   450  //否则返回给定的哈希数组。
   451  func returnHashes(hashes []common.Hash) []common.Hash {
   452  	if hashes == nil {
   453  		return []common.Hash{}
   454  	}
   455  	return hashes
   456  }
   457  
   458  //ReturnLogs是一个帮助程序,当给定的日志数组为零时,它将返回空的日志数组。
   459  //否则返回给定的logs数组。
   460  func returnLogs(logs []*types.Log) []*types.Log {
   461  	if logs == nil {
   462  		return []*types.Log{}
   463  	}
   464  	return logs
   465  }
   466  
   467  //用给定的数据取消标记JSON集合*参数字段。
   468  func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
   469  	type input struct {
   470  		BlockHash *common.Hash     `json:"blockHash"`
   471  		FromBlock *rpc.BlockNumber `json:"fromBlock"`
   472  		ToBlock   *rpc.BlockNumber `json:"toBlock"`
   473  		Addresses interface{}      `json:"address"`
   474  		Topics    []interface{}    `json:"topics"`
   475  	}
   476  
   477  	var raw input
   478  	if err := json.Unmarshal(data, &raw); err != nil {
   479  		return err
   480  	}
   481  
   482  	if raw.BlockHash != nil {
   483  		if raw.FromBlock != nil || raw.ToBlock != nil {
   484  //blockhash与fromblock/toblock条件互斥
   485  			return fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other")
   486  		}
   487  		args.BlockHash = raw.BlockHash
   488  	} else {
   489  		if raw.FromBlock != nil {
   490  			args.FromBlock = big.NewInt(raw.FromBlock.Int64())
   491  		}
   492  
   493  		if raw.ToBlock != nil {
   494  			args.ToBlock = big.NewInt(raw.ToBlock.Int64())
   495  		}
   496  	}
   497  
   498  	args.Addresses = []common.Address{}
   499  
   500  	if raw.Addresses != nil {
   501  //原始地址可以包含单个地址或地址数组
   502  		switch rawAddr := raw.Addresses.(type) {
   503  		case []interface{}:
   504  			for i, addr := range rawAddr {
   505  				if strAddr, ok := addr.(string); ok {
   506  					addr, err := decodeAddress(strAddr)
   507  					if err != nil {
   508  						return fmt.Errorf("invalid address at index %d: %v", i, err)
   509  					}
   510  					args.Addresses = append(args.Addresses, addr)
   511  				} else {
   512  					return fmt.Errorf("non-string address at index %d", i)
   513  				}
   514  			}
   515  		case string:
   516  			addr, err := decodeAddress(rawAddr)
   517  			if err != nil {
   518  				return fmt.Errorf("invalid address: %v", err)
   519  			}
   520  			args.Addresses = []common.Address{addr}
   521  		default:
   522  			return errors.New("invalid addresses in query")
   523  		}
   524  	}
   525  
   526  //主题是由字符串和/或字符串数组组成的数组。
   527  //JSON空值转换为common.hash并被筛选器管理器忽略。
   528  	if len(raw.Topics) > 0 {
   529  		args.Topics = make([][]common.Hash, len(raw.Topics))
   530  		for i, t := range raw.Topics {
   531  			switch topic := t.(type) {
   532  			case nil:
   533  //匹配日志时忽略主题
   534  
   535  			case string:
   536  //匹配特定主题
   537  				top, err := decodeTopic(topic)
   538  				if err != nil {
   539  					return err
   540  				}
   541  				args.Topics[i] = []common.Hash{top}
   542  
   543  			case []interface{}:
   544  //或案例,例如[空,“topic0”,“topic1”]
   545  				for _, rawTopic := range topic {
   546  					if rawTopic == nil {
   547  //空组件,全部匹配
   548  						args.Topics[i] = nil
   549  						break
   550  					}
   551  					if topic, ok := rawTopic.(string); ok {
   552  						parsed, err := decodeTopic(topic)
   553  						if err != nil {
   554  							return err
   555  						}
   556  						args.Topics[i] = append(args.Topics[i], parsed)
   557  					} else {
   558  						return fmt.Errorf("invalid topic(s)")
   559  					}
   560  				}
   561  			default:
   562  				return fmt.Errorf("invalid topic(s)")
   563  			}
   564  		}
   565  	}
   566  
   567  	return nil
   568  }
   569  
   570  func decodeAddress(s string) (common.Address, error) {
   571  	b, err := hexutil.Decode(s)
   572  	if err == nil && len(b) != common.AddressLength {
   573  		err = fmt.Errorf("hex has invalid length %d after decoding; expected %d for address", len(b), common.AddressLength)
   574  	}
   575  	return common.BytesToAddress(b), err
   576  }
   577  
   578  func decodeTopic(s string) (common.Hash, error) {
   579  	b, err := hexutil.Decode(s)
   580  	if err == nil && len(b) != common.HashLength {
   581  		err = fmt.Errorf("hex has invalid length %d after decoding; expected %d for topic", len(b), common.HashLength)
   582  	}
   583  	return common.BytesToHash(b), err
   584  }