github.com/turingchain2020/turingchain@v1.1.21/blockchain/push.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"io/ioutil"
     7  	"net"
     8  	"net/http"
     9  	"sync"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	"github.com/turingchain2020/turingchain/common"
    14  	dbm "github.com/turingchain2020/turingchain/common/db"
    15  	"github.com/turingchain2020/turingchain/types"
    16  )
    17  
    18  const (
    19  	notRunning               = int32(1)
    20  	running                  = int32(2)
    21  	pushBlockMaxSeq          = 10
    22  	pushTxReceiptMaxSeq      = 100
    23  	pushMaxSize              = 1 * 1024 * 1024
    24  	maxPushSubscriber        = int(100)
    25  	subscribeStatusActive    = int32(1)
    26  	subscribeStatusNotActive = int32(2)
    27  	postFail2Sleep           = int32(60) //一次发送失败,sleep的次数
    28  	chanBufCap               = int(10)
    29  )
    30  
    31  // Push types ID
    32  const (
    33  	PushBlock       = int32(0)
    34  	PushBlockHeader = int32(1)
    35  	PushTxReceipt   = int32(2)
    36  	PushTxResult    = int32(3)
    37  )
    38  
    39  // CommonStore 通用的store 接口
    40  // 修改大一点,可能可以用 db.KVDB
    41  // 先改动小一点, 用store, 如果接口一样可以直接换
    42  type CommonStore interface {
    43  	SetSync(key, value []byte) error
    44  	Set(key, value []byte) error
    45  	GetKey(key []byte) ([]byte, error)
    46  	PrefixCount(prefix []byte) int64
    47  	List(prefix []byte) ([][]byte, error)
    48  }
    49  
    50  //SequenceStore ...
    51  type SequenceStore interface {
    52  	LoadBlockLastSequence() (int64, error)
    53  	// seqUpdateChan -> block sequence
    54  	GetBlockSequence(seq int64) (*types.BlockSequence, error)
    55  	// hash -> block header
    56  	GetBlockHeaderByHash(hash []byte) (*types.Header, error)
    57  	// seqUpdateChan -> block, size
    58  	LoadBlockBySequence(seq int64) (*types.BlockDetail, int, error)
    59  	// get last header
    60  	LastHeader() *types.Header
    61  	// hash -> seqUpdateChan
    62  	GetSequenceByHash(hash []byte) (int64, error)
    63  }
    64  
    65  //PostService ...
    66  type PostService interface {
    67  	PostData(subscribe *types.PushSubscribeReq, postdata []byte, seq int64) (err error)
    68  }
    69  
    70  //当前的实现是为每个订阅者单独启动一个协程goroute,然后单独为每个subscriber分别过滤指定类型的交易,
    71  //进行归类,这种方式集成了区块推送方式的处理机制,但是对于订阅者数量大的情况,势必会浪费cpu的开销,
    72  //数据库的读取开销不会额外增加明星,因为会有cach
    73  //TODO:后续需要考虑将区块推送和交易执行回执推送进行重构,提高并行推送效率
    74  //pushNotify push Notify
    75  type pushNotify struct {
    76  	subscribe      *types.PushSubscribeReq
    77  	seqUpdateChan  chan int64
    78  	closechan      chan struct{}
    79  	status         int32
    80  	postFail2Sleep int32
    81  }
    82  
    83  //Push ...
    84  type Push struct {
    85  	store          CommonStore
    86  	sequenceStore  SequenceStore
    87  	tasks          map[string]*pushNotify
    88  	mu             sync.Mutex
    89  	postService    PostService
    90  	cfg            *types.TuringchainConfig
    91  	postFail2Sleep int32
    92  	postwg         *sync.WaitGroup
    93  }
    94  
    95  //PushClient ...
    96  type PushClient struct {
    97  	client *http.Client
    98  }
    99  
   100  // PushType ...
   101  type PushType int32
   102  
   103  func (pushType PushType) string() string {
   104  	return []string{"PushBlock", "PushBlockHeader", "PushTxReceipt", "PushTxResult", "NotSupported"}[pushType]
   105  }
   106  
   107  //PostData ...
   108  func (pushClient *PushClient) PostData(subscribe *types.PushSubscribeReq, postdata []byte, seq int64) (err error) {
   109  	//post data in body
   110  	chainlog.Info("postData begin", "seq", seq, "subscribe name", subscribe.Name)
   111  	var buf bytes.Buffer
   112  	g := gzip.NewWriter(&buf)
   113  	if _, err = g.Write(postdata); err != nil {
   114  		return err
   115  	}
   116  	if err = g.Close(); err != nil {
   117  		return err
   118  	}
   119  
   120  	req, err := http.NewRequest("POST", subscribe.URL, &buf)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	req.Header.Set("Content-Type", "text/plain")
   126  	req.Header.Set("Content-Encoding", "gzip")
   127  	resp, err := pushClient.client.Do(req)
   128  	if err != nil {
   129  		chainlog.Info("postData", "Do err", err)
   130  		return err
   131  	}
   132  	body, err := ioutil.ReadAll(resp.Body)
   133  	if err != nil {
   134  		_ = resp.Body.Close()
   135  		return err
   136  	}
   137  	if string(body) != "ok" && string(body) != "OK" {
   138  		chainlog.Error("postData fail", "name:", subscribe.Name, "URL", subscribe.URL,
   139  			"Contract:", subscribe.Contract, "body", string(body))
   140  		_ = resp.Body.Close()
   141  		return types.ErrPushSeqPostData
   142  	}
   143  	chainlog.Debug("postData success", "name", subscribe.Name, "URL", subscribe.URL,
   144  		"Contract:", subscribe.Contract, "updateSeq", seq)
   145  	return resp.Body.Close()
   146  }
   147  
   148  //ProcAddBlockSeqCB 添加seq callback
   149  func (chain *BlockChain) procSubscribePush(subscribe *types.PushSubscribeReq) error {
   150  	if !chain.enablePushSubscribe {
   151  		chainlog.Error("Push is not enabled for subscribed")
   152  		return types.ErrPushNotSupport
   153  	}
   154  
   155  	if !chain.isRecordBlockSequence {
   156  		chainlog.Error("procSubscribePush not support sequence")
   157  		return types.ErrRecordBlockSequence
   158  	}
   159  
   160  	if subscribe == nil {
   161  		chainlog.Error("procSubscribePush para is null")
   162  		return types.ErrInvalidParam
   163  	}
   164  
   165  	if chain.client.GetConfig().IsEnable("reduceLocaldb") && subscribe.Type == PushTxReceipt {
   166  		chainlog.Error("Tx receipts are reduced on this node")
   167  		return types.ErrTxReceiptReduced
   168  	}
   169  	return chain.push.addSubscriber(subscribe)
   170  }
   171  
   172  //ProcListPush 列出所有已经设置的推送订阅
   173  func (chain *BlockChain) ProcListPush() (*types.PushSubscribes, error) {
   174  	if !chain.isRecordBlockSequence {
   175  		return nil, types.ErrRecordBlockSequence
   176  	}
   177  	if !chain.enablePushSubscribe {
   178  		return nil, types.ErrPushNotSupport
   179  	}
   180  
   181  	values, err := chain.push.store.List(pushPrefix)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	var listSeqCBs types.PushSubscribes
   186  	for _, value := range values {
   187  		var onePush types.PushWithStatus
   188  		err := types.Decode(value, &onePush)
   189  		if err != nil {
   190  			return nil, err
   191  		}
   192  		listSeqCBs.Pushes = append(listSeqCBs.Pushes, onePush.Push)
   193  	}
   194  	return &listSeqCBs, nil
   195  }
   196  
   197  // ProcGetLastPushSeq Seq的合法值从0开始的,所以没有获取到或者获取失败都应该返回-1
   198  func (chain *BlockChain) ProcGetLastPushSeq(name string) (int64, error) {
   199  	if !chain.isRecordBlockSequence {
   200  		return -1, types.ErrRecordBlockSequence
   201  	}
   202  	if !chain.enablePushSubscribe {
   203  		return -1, types.ErrPushNotSupport
   204  	}
   205  
   206  	lastSeqbytes, err := chain.push.store.GetKey(calcLastPushSeqNumKey(name))
   207  	if lastSeqbytes == nil || err != nil {
   208  		if err != dbm.ErrNotFoundInDb {
   209  			storeLog.Error("getSeqCBLastNum", "error", err)
   210  		}
   211  		return -1, types.ErrPushNotSubscribed
   212  	}
   213  	n, err := decodeHeight(lastSeqbytes)
   214  	if err != nil {
   215  		return -1, err
   216  	}
   217  	storeLog.Error("getSeqCBLastNum", "name", name, "num", n)
   218  
   219  	return n, nil
   220  }
   221  
   222  func newpush(commonStore CommonStore, seqStore SequenceStore, cfg *types.TuringchainConfig) *Push {
   223  	tasks := make(map[string]*pushNotify)
   224  
   225  	pushClient := &PushClient{
   226  		client: &http.Client{Transport: &http.Transport{
   227  			Dial: (&net.Dialer{
   228  				Timeout:   30 * time.Second,
   229  				KeepAlive: 30 * time.Second,
   230  			}).Dial,
   231  			TLSHandshakeTimeout:   10 * time.Second,
   232  			ResponseHeaderTimeout: 10 * time.Second,
   233  			ExpectContinueTimeout: 1 * time.Second,
   234  		}},
   235  	}
   236  	service := &Push{store: commonStore,
   237  		sequenceStore:  seqStore,
   238  		tasks:          tasks,
   239  		postService:    pushClient,
   240  		cfg:            cfg,
   241  		postFail2Sleep: postFail2Sleep,
   242  		postwg:         &sync.WaitGroup{},
   243  	}
   244  	service.init()
   245  
   246  	return service
   247  }
   248  
   249  //初始化: 从数据库读出seq的数目
   250  func (push *Push) init() {
   251  	var subscribes []*types.PushSubscribeReq
   252  	values, err := push.store.List(pushPrefix)
   253  	if err != nil && err != dbm.ErrNotFoundInDb {
   254  		chainlog.Error("Push init", "err", err)
   255  		return
   256  	}
   257  	if 0 == len(values) {
   258  		return
   259  	}
   260  	for _, value := range values {
   261  		var pushWithStatus types.PushWithStatus
   262  		err := types.Decode(value, &pushWithStatus)
   263  		if err != nil {
   264  			chainlog.Error("Push init", "Failed to decode subscribe due to err:", err)
   265  			return
   266  		}
   267  		if pushWithStatus.Status == subscribeStatusActive {
   268  			subscribes = append(subscribes, pushWithStatus.Push)
   269  		}
   270  
   271  	}
   272  	for _, subscribe := range subscribes {
   273  		push.addTask(subscribe)
   274  	}
   275  }
   276  
   277  // Close ...
   278  func (push *Push) Close() {
   279  	push.mu.Lock()
   280  	for _, task := range push.tasks {
   281  		close(task.closechan)
   282  	}
   283  	push.mu.Unlock()
   284  	push.postwg.Wait()
   285  }
   286  
   287  func (push *Push) addSubscriber(subscribe *types.PushSubscribeReq) error {
   288  	if subscribe == nil {
   289  		chainlog.Error("addSubscriber input para is null")
   290  		return types.ErrInvalidParam
   291  	}
   292  
   293  	if subscribe.Type < PushBlock || subscribe.Type > PushTxResult {
   294  		chainlog.Error("addSubscriber input type is error", "type", subscribe.Type)
   295  		return types.ErrInvalidParam
   296  	}
   297  
   298  	//如果需要配置起始的块的信息,则为了保持一致性,三项缺一不可
   299  	if subscribe.LastBlockHash != "" || subscribe.LastSequence != 0 || subscribe.LastHeight != 0 {
   300  		if subscribe.LastBlockHash == "" || subscribe.LastSequence == 0 || subscribe.LastHeight == 0 {
   301  			chainlog.Error("addSubscriber ErrInvalidParam", "seqUpdateChan", subscribe.LastSequence, "height", subscribe.LastHeight, "hash", subscribe.LastBlockHash)
   302  			return types.ErrInvalidParam
   303  		}
   304  	}
   305  
   306  	//如果该用户已经注册了订阅请求,则只是确认是否需用重新启动,否则就直接返回
   307  	if exist, subscribeInDB := push.hasSubscriberExist(subscribe); exist {
   308  		if subscribeInDB.URL != subscribe.URL || subscribeInDB.Type != subscribe.Type {
   309  			return types.ErrNotAllowModifyPush
   310  		}
   311  		//使用保存在数据库中的push配置,而不是最新的配置信息
   312  		return push.check2ResumePush(subscribeInDB)
   313  	}
   314  
   315  	push.mu.Lock()
   316  	if len(push.tasks) >= maxPushSubscriber {
   317  		chainlog.Error("addSubscriber too many push subscriber")
   318  		push.mu.Unlock()
   319  		return types.ErrTooManySeqCB
   320  	}
   321  	push.mu.Unlock()
   322  
   323  	//处理需要从指定高度开始推送的订阅请求
   324  	if subscribe.LastSequence > 0 {
   325  		sequence, err := push.sequenceStore.GetBlockSequence(subscribe.LastSequence)
   326  		if err != nil {
   327  			chainlog.Error("addSubscriber continue-seqUpdateChan-push", "load-1", err)
   328  			return err
   329  		}
   330  
   331  		// 注册点,在节点上存在
   332  		// 同一高度,不一定同一个hash,有分叉的可能;但同一个hash必定同一个高度
   333  		reloadHash := common.ToHex(sequence.Hash)
   334  		if subscribe.LastBlockHash == reloadHash {
   335  			// 先填入last seqUpdateChan, 而不是从0开始
   336  			err = push.setLastPushSeq(subscribe.Name, subscribe.LastSequence)
   337  			if err != nil {
   338  				chainlog.Error("addSubscriber", "setLastPushSeq", err)
   339  				return err
   340  			}
   341  			return push.persisAndStart(subscribe)
   342  		}
   343  	}
   344  
   345  	return push.persisAndStart(subscribe)
   346  }
   347  
   348  func (push *Push) hasSubscriberExist(subscribe *types.PushSubscribeReq) (bool, *types.PushSubscribeReq) {
   349  	value, err := push.store.GetKey(calcPushKey(subscribe.Name))
   350  	if err == nil {
   351  		var pushWithStatus types.PushWithStatus
   352  		err = types.Decode(value, &pushWithStatus)
   353  		return err == nil, pushWithStatus.Push
   354  	}
   355  	return false, nil
   356  }
   357  
   358  func (push *Push) subscriberCount() int64 {
   359  	return push.store.PrefixCount(pushPrefix)
   360  }
   361  
   362  //向数据库添加交易回执订阅信息
   363  func (push *Push) persisAndStart(subscribe *types.PushSubscribeReq) error {
   364  	if len(subscribe.Name) > 128 || len(subscribe.URL) > 1024 || len(subscribe.URL) == 0 {
   365  		storeLog.Error("Invalid para to persisAndStart due to wrong length", "len(subscribe.Name)=", len(subscribe.Name),
   366  			"len(subscribe.URL)=", len(subscribe.URL), "len(subscribe.Contract)=", len(subscribe.Contract))
   367  		return types.ErrInvalidParam
   368  	}
   369  	key := calcPushKey(subscribe.Name)
   370  	storeLog.Info("persisAndStart", "key", string(key), "subscribe", subscribe)
   371  	push.addTask(subscribe)
   372  
   373  	pushWithStatus := &types.PushWithStatus{
   374  		Push:   subscribe,
   375  		Status: subscribeStatusActive,
   376  	}
   377  
   378  	return push.store.SetSync(key, types.Encode(pushWithStatus))
   379  }
   380  
   381  func (push *Push) check2ResumePush(subscribe *types.PushSubscribeReq) error {
   382  	if len(subscribe.Name) > 128 || len(subscribe.URL) > 1024 || len(subscribe.Contract) > 128 {
   383  		storeLog.Error("Invalid para to persisAndStart due to wrong length", "len(subscribe.Name)=", len(subscribe.Name),
   384  			"len(subscribe.URL)=", len(subscribe.URL), "len(subscribe.Contract)=", len(subscribe.Contract))
   385  		return types.ErrInvalidParam
   386  	}
   387  	push.mu.Lock()
   388  	defer push.mu.Unlock()
   389  
   390  	keyStr := string(calcPushKey(subscribe.Name))
   391  	storeLog.Info("check2ResumePush", "key", keyStr, "subscribe", subscribe)
   392  
   393  	notify := push.tasks[keyStr]
   394  	//有可能因为连续发送失败已经导致将其从推送任务中删除了
   395  	if nil == notify {
   396  		push.tasks[keyStr] = &pushNotify{
   397  			subscribe:     subscribe,
   398  			seqUpdateChan: make(chan int64, chanBufCap),
   399  			closechan:     make(chan struct{}),
   400  			status:        notRunning,
   401  		}
   402  		push.runTask(push.tasks[keyStr])
   403  		storeLog.Info("check2ResumePush new pushNotify created")
   404  		return nil
   405  	}
   406  
   407  	if running == atomic.LoadInt32(&notify.status) {
   408  		storeLog.Info("Is already in state:running", "postFail2Sleep", atomic.LoadInt32(&notify.postFail2Sleep))
   409  		atomic.StoreInt32(&notify.postFail2Sleep, 0)
   410  		return nil
   411  	}
   412  	storeLog.Info("check2ResumePush to resume a push", "name", subscribe.Name)
   413  
   414  	push.runTask(push.tasks[keyStr])
   415  	return nil
   416  }
   417  
   418  //每次add一个新push时,发送最新的seq
   419  func (push *Push) updateLastSeq(name string) {
   420  	last, err := push.sequenceStore.LoadBlockLastSequence()
   421  	if err != nil {
   422  		chainlog.Error("LoadBlockLastSequence", "err", err)
   423  		return
   424  	}
   425  
   426  	notify := push.tasks[string(calcPushKey(name))]
   427  	notify.seqUpdateChan <- last
   428  	chainlog.Debug("updateLastSeq", "last", last, "notify.seqUpdateChan", len(notify.seqUpdateChan))
   429  }
   430  
   431  // addTask 每个name 有一个task, 通知新增推送
   432  func (push *Push) addTask(subscribe *types.PushSubscribeReq) {
   433  	push.mu.Lock()
   434  	defer push.mu.Unlock()
   435  	keyStr := string(calcPushKey(subscribe.Name))
   436  	push.tasks[keyStr] = &pushNotify{
   437  		subscribe:      subscribe,
   438  		seqUpdateChan:  make(chan int64, chanBufCap),
   439  		closechan:      make(chan struct{}),
   440  		status:         notRunning,
   441  		postFail2Sleep: 0,
   442  	}
   443  
   444  	push.runTask(push.tasks[keyStr])
   445  }
   446  
   447  func trigeRun(run chan struct{}, sleep time.Duration, name string) {
   448  	chainlog.Info("trigeRun", name, "name", "sleep", sleep, "run len", len(run))
   449  	if sleep > 0 {
   450  		time.Sleep(sleep)
   451  	}
   452  	go func() {
   453  		run <- struct{}{}
   454  	}()
   455  }
   456  
   457  func (push *Push) runTask(input *pushNotify) {
   458  	//触发goroutine运行
   459  	push.updateLastSeq(input.subscribe.Name)
   460  
   461  	go func(in *pushNotify) {
   462  		var lastesBlockSeq int64
   463  		var continueFailCount int32
   464  		var err error
   465  
   466  		subscribe := in.subscribe
   467  		lastProcessedseq := push.getLastPushSeq(subscribe)
   468  
   469  		atomic.StoreInt32(&in.status, running)
   470  
   471  		runChan := make(chan struct{}, 10)
   472  		pushMaxSeq := pushBlockMaxSeq
   473  		if subscribe.Type == PushTxReceipt {
   474  			pushMaxSeq = pushTxReceiptMaxSeq
   475  		}
   476  
   477  		chainlog.Debug("start push with info", "subscribe name", subscribe.Name, "Type", PushType(subscribe.Type).string())
   478  		for {
   479  			select {
   480  			case <-runChan:
   481  				if atomic.LoadInt32(&input.postFail2Sleep) > 0 {
   482  					if postFail2SleepNew := atomic.AddInt32(&input.postFail2Sleep, -1); postFail2SleepNew > 0 {
   483  						chainlog.Debug("wait another ticker for post fail", "postFail2Sleep", postFail2SleepNew, "name", in.subscribe.Name)
   484  						trigeRun(runChan, time.Second, subscribe.Name)
   485  						continue
   486  					}
   487  				}
   488  
   489  			case lastestSeq := <-in.seqUpdateChan:
   490  				chainlog.Debug("runTask recv:", "lastestSeq", lastestSeq, "subscribe name", subscribe.Name, "Type", PushType(subscribe.Type).string())
   491  				//首先判断是否存在发送失败的情况,如果存在,则进行进行sleep操作
   492  				if atomic.LoadInt32(&input.postFail2Sleep) > 0 {
   493  					if postFail2SleepNew := atomic.AddInt32(&input.postFail2Sleep, -1); postFail2SleepNew > 0 {
   494  						chainlog.Debug("wait another ticker for post fail", "postFail2Sleep", postFail2SleepNew, "name", in.subscribe.Name)
   495  						trigeRun(runChan, time.Second, subscribe.Name)
   496  						continue
   497  					}
   498  				}
   499  				//获取当前最新的sequence,这样就可以一次性发送多个区块的信息,而不需要每次从通知chan中获取最新sequence
   500  				if lastesBlockSeq, err = push.sequenceStore.LoadBlockLastSequence(); err != nil {
   501  					chainlog.Error("LoadBlockLastSequence", "err", err)
   502  					return
   503  				}
   504  
   505  				//没有更新的区块,则不进行处理,同时等待一定的时间
   506  				if lastProcessedseq >= lastesBlockSeq {
   507  					continue
   508  				}
   509  				chainlog.Debug("another new block", "subscribe name", subscribe.Name, "Type", PushType(subscribe.Type).string(),
   510  					"last push sequence", lastProcessedseq, "lastest sequence", lastesBlockSeq,
   511  					"time second", time.Now().Second())
   512  				//确定一次推送的数量,如果需要更新的数量少于门限值,则一次只推送一个区块的交易数据
   513  				seqCount := pushMaxSeq
   514  				if seqCount > int(lastesBlockSeq-lastProcessedseq) {
   515  					seqCount = int(lastesBlockSeq - lastProcessedseq)
   516  				}
   517  
   518  				data, updateSeq, err := push.getPushData(subscribe, lastProcessedseq+1, seqCount, pushMaxSize)
   519  				if err != nil {
   520  					chainlog.Error("getPushData", "err", err, "seqCurrent", lastProcessedseq+1, "maxSeq", seqCount,
   521  						"Name", subscribe.Name, "pushType:", PushType(subscribe.Type).string())
   522  					continue
   523  				}
   524  
   525  				if data != nil {
   526  					err = push.postService.PostData(subscribe, data, updateSeq)
   527  					if err != nil {
   528  						continueFailCount++
   529  						chainlog.Error("postdata failed", "err", err, "lastProcessedseq", lastProcessedseq,
   530  							"Name", subscribe.Name, "pushType:", PushType(subscribe.Type).string(), "continueFailCount", continueFailCount)
   531  						if continueFailCount >= 3 {
   532  							atomic.StoreInt32(&in.status, notRunning)
   533  							chainlog.Error("postdata failed exceed 3 times", "Name", subscribe.Name, "in.status", atomic.LoadInt32(&in.status))
   534  
   535  							pushWithStatus := &types.PushWithStatus{
   536  								Push:   subscribe,
   537  								Status: subscribeStatusNotActive,
   538  							}
   539  
   540  							key := calcPushKey(subscribe.Name)
   541  							push.mu.Lock()
   542  							delete(push.tasks, string(key))
   543  							push.mu.Unlock()
   544  							_ = push.store.SetSync(key, types.Encode(pushWithStatus))
   545  							push.postwg.Done()
   546  							return
   547  						}
   548  						//sleep 60s,每次1s,总计60次,在每次结束时,等待接收方重新进行请求推送
   549  						atomic.StoreInt32(&input.postFail2Sleep, push.postFail2Sleep)
   550  						trigeRun(runChan, time.Second, subscribe.Name)
   551  						continue
   552  					}
   553  					_ = push.setLastPushSeq(subscribe.Name, updateSeq)
   554  				}
   555  				continueFailCount = 0
   556  				lastProcessedseq = updateSeq
   557  				// 在联盟链情况下, 无新增交易的情况下, 不会完成从新开始同步
   558  				// 在公链情况下, 需要有新区块才能触发推送,
   559  				// 所以这里在未同步到最新区块, 需要主动触发同步
   560  				if lastProcessedseq < lastesBlockSeq {
   561  					push.mu.Lock()
   562  					if len(in.seqUpdateChan) == 0 {
   563  						in.seqUpdateChan <- lastesBlockSeq
   564  					}
   565  					push.mu.Unlock()
   566  				}
   567  			case <-in.closechan:
   568  				push.postwg.Done()
   569  				chainlog.Info("getPushData", "push task closed for subscribe", subscribe.Name)
   570  				return
   571  			}
   572  		}
   573  
   574  	}(input)
   575  	push.postwg.Add(1)
   576  }
   577  
   578  // UpdateSeq sequence 更新通知
   579  func (push *Push) UpdateSeq(seq int64) {
   580  	push.mu.Lock()
   581  	defer push.mu.Unlock()
   582  	for _, notify := range push.tasks {
   583  		//再写入seq(一定不会block,因为加了lock,不存在两个同时写channel的情况)
   584  		if len(notify.seqUpdateChan) < chanBufCap {
   585  			chainlog.Info("new block Update Seq notified", "subscribe", notify.subscribe.Name, "current sequence", seq, "length", len(notify.seqUpdateChan))
   586  			notify.seqUpdateChan <- seq
   587  		}
   588  		chainlog.Info("new block UpdateSeq", "subscribe", notify.subscribe.Name, "current sequence", seq, "length", len(notify.seqUpdateChan))
   589  	}
   590  }
   591  
   592  func (push *Push) getPushData(subscribe *types.PushSubscribeReq, startSeq int64, seqCount, maxSize int) ([]byte, int64, error) {
   593  	if subscribe.Type == PushBlock {
   594  		return push.getBlockSeqs(subscribe.Encode, startSeq, seqCount, maxSize)
   595  	} else if subscribe.Type == PushBlockHeader {
   596  		return push.getHeaderSeqs(subscribe.Encode, startSeq, seqCount, maxSize)
   597  	} else if subscribe.Type == PushTxResult {
   598  		return push.getTxResults(subscribe.Encode, startSeq, seqCount)
   599  	}
   600  	return push.getTxReceipts(subscribe, startSeq, seqCount, maxSize)
   601  }
   602  
   603  func (push *Push) getTxReceipts(subscribe *types.PushSubscribeReq, startSeq int64, seqCount, maxSize int) ([]byte, int64, error) {
   604  	txReceipts := &types.TxReceipts4Subscribe{}
   605  	totalSize := 0
   606  	actualIterCount := 0
   607  	for i := startSeq; i < startSeq+int64(seqCount); i++ {
   608  		chainlog.Info("getTxReceipts", "startSeq:", i)
   609  		seqdata, err := push.sequenceStore.GetBlockSequence(i)
   610  		if err != nil {
   611  			return nil, -1, err
   612  		}
   613  		detail, _, err := push.sequenceStore.LoadBlockBySequence(i)
   614  		if err != nil {
   615  			return nil, -1, err
   616  		}
   617  
   618  		txReceiptsPerBlk := &types.TxReceipts4SubscribePerBlk{}
   619  		chainlog.Info("getTxReceipts", "height:", detail.Block.Height, "tx numbers:", len(detail.Block.Txs), "Receipts numbers:", len(detail.Receipts))
   620  		for txIndex, tx := range detail.Block.Txs {
   621  			if subscribe.Contract[string(tx.Execer)] {
   622  				chainlog.Info("getTxReceipts", "txIndex:", txIndex)
   623  				txReceiptsPerBlk.Tx = append(txReceiptsPerBlk.Tx, tx)
   624  				txReceiptsPerBlk.ReceiptData = append(txReceiptsPerBlk.ReceiptData, detail.Receipts[txIndex])
   625  				//txReceiptsPerBlk.KV = append(txReceiptsPerBlk.KV, detail.KV[txIndex])
   626  			}
   627  		}
   628  		if len(txReceiptsPerBlk.Tx) > 0 {
   629  			txReceiptsPerBlk.Height = detail.Block.Height
   630  			txReceiptsPerBlk.BlockHash = detail.Block.Hash(push.cfg)
   631  			txReceiptsPerBlk.ParentHash = detail.Block.ParentHash
   632  			txReceiptsPerBlk.PreviousHash = []byte{}
   633  			txReceiptsPerBlk.AddDelType = int32(seqdata.Type)
   634  			txReceiptsPerBlk.SeqNum = i
   635  		}
   636  		size := types.Size(txReceiptsPerBlk)
   637  		if len(txReceiptsPerBlk.Tx) > 0 && totalSize+size < maxSize {
   638  			txReceipts.TxReceipts = append(txReceipts.TxReceipts, txReceiptsPerBlk)
   639  			totalSize += size
   640  			chainlog.Debug("get Tx Receipts subscribed for pushing", "Name", subscribe.Name, "contract:", subscribe.Contract,
   641  				"height=", txReceiptsPerBlk.Height)
   642  		} else if totalSize+size > maxSize {
   643  			break
   644  		}
   645  		actualIterCount++
   646  	}
   647  
   648  	updateSeq := startSeq + int64(actualIterCount) - 1
   649  	if len(txReceipts.TxReceipts) == 0 {
   650  		return nil, updateSeq, nil
   651  	}
   652  	chainlog.Info("getTxReceipts", "updateSeq", updateSeq, "actualIterCount", actualIterCount)
   653  
   654  	var postdata []byte
   655  	var err error
   656  	if subscribe.Encode == "json" {
   657  		postdata, err = types.PBToJSON(txReceipts)
   658  		if err != nil {
   659  			return nil, -1, err
   660  		}
   661  	} else {
   662  		postdata = types.Encode(txReceipts)
   663  	}
   664  
   665  	return postdata, updateSeq, nil
   666  }
   667  
   668  func (push *Push) getBlockDataBySeq(seq int64) (*types.BlockSeq, int, error) {
   669  	seqdata, err := push.sequenceStore.GetBlockSequence(seq)
   670  	if err != nil {
   671  		return nil, 0, err
   672  	}
   673  	detail, blockSize, err := push.sequenceStore.LoadBlockBySequence(seq)
   674  	if err != nil {
   675  		return nil, 0, err
   676  	}
   677  	return &types.BlockSeq{Num: seq, Seq: seqdata, Detail: detail}, blockSize, nil
   678  }
   679  
   680  func (push *Push) getTxResults(encode string, seq int64, seqCount int) ([]byte, int64, error) {
   681  	var txResultSeqs types.TxResultSeqs
   682  	for i := seq; i < seq+int64(seqCount); i++ {
   683  		blockSeq, _, err := push.getBlockDataBySeq(i)
   684  		if err != nil {
   685  			return nil, -1, err
   686  		}
   687  		txResults := types.TxResultPerBlock{
   688  			Items:      make([]*types.TxHashWithReceiptType, len(blockSeq.Detail.Receipts)),
   689  			Height:     blockSeq.Detail.Block.Height,
   690  			BlockHash:  blockSeq.Detail.Block.Hash(push.cfg),
   691  			ParentHash: blockSeq.Detail.Block.ParentHash,
   692  			AddDelType: int32(blockSeq.Seq.Type),
   693  			SeqNum:     blockSeq.Num,
   694  		}
   695  		for i := range txResults.Items {
   696  			txResults.Items[i] = &types.TxHashWithReceiptType{
   697  				Hash: blockSeq.Detail.Block.Txs[i].Hash(),
   698  				Ty:   blockSeq.Detail.Receipts[i].Ty,
   699  			}
   700  		}
   701  		txResultSeqs.Items = append(txResultSeqs.Items, &txResults)
   702  	}
   703  
   704  	var postdata []byte
   705  	var err error
   706  	if encode == "json" {
   707  		postdata, err = types.PBToJSON(&txResultSeqs)
   708  		if err != nil {
   709  			return nil, -1, err
   710  		}
   711  	} else {
   712  		postdata = types.Encode(&txResultSeqs)
   713  	}
   714  	return postdata, txResultSeqs.Items[0].SeqNum + int64(len(txResultSeqs.Items)) - 1, nil
   715  }
   716  
   717  func (push *Push) getBlockSeqs(encode string, seq int64, seqCount, maxSize int) ([]byte, int64, error) {
   718  	seqs := &types.BlockSeqs{}
   719  	totalSize := 0
   720  	for i := 0; i < seqCount; i++ {
   721  		seq, size, err := push.getBlockDataBySeq(seq + int64(i))
   722  		if err != nil {
   723  			return nil, -1, err
   724  		}
   725  		if totalSize == 0 || totalSize+size < maxSize {
   726  			seqs.Seqs = append(seqs.Seqs, seq)
   727  			totalSize += size
   728  		} else {
   729  			break
   730  		}
   731  	}
   732  	updateSeq := seqs.Seqs[0].Num + int64(len(seqs.Seqs)) - 1
   733  
   734  	var postdata []byte
   735  	var err error
   736  	if encode == "json" {
   737  		postdata, err = types.PBToJSON(seqs)
   738  		if err != nil {
   739  			return nil, -1, err
   740  		}
   741  	} else {
   742  		postdata = types.Encode(seqs)
   743  	}
   744  	return postdata, updateSeq, nil
   745  }
   746  
   747  func (push *Push) getHeaderSeqs(encode string, seq int64, seqCount, maxSize int) ([]byte, int64, error) {
   748  	seqs := &types.HeaderSeqs{}
   749  	totalSize := 0
   750  	for i := 0; i < seqCount; i++ {
   751  		seq, size, err := push.getHeaderDataBySeq(seq + int64(i))
   752  		if err != nil {
   753  			return nil, -1, err
   754  		}
   755  		if totalSize == 0 || totalSize+size < maxSize {
   756  			seqs.Seqs = append(seqs.Seqs, seq)
   757  			totalSize += size
   758  		} else {
   759  			break
   760  		}
   761  	}
   762  	updateSeq := seqs.Seqs[0].Num + int64(len(seqs.Seqs)) - 1
   763  
   764  	var postdata []byte
   765  	var err error
   766  
   767  	if encode == "json" {
   768  		postdata, err = types.PBToJSON(seqs)
   769  		if err != nil {
   770  			return nil, -1, err
   771  		}
   772  	} else {
   773  		postdata = types.Encode(seqs)
   774  	}
   775  	return postdata, updateSeq, nil
   776  }
   777  
   778  func (push *Push) getHeaderDataBySeq(seq int64) (*types.HeaderSeq, int, error) {
   779  	seqdata, err := push.sequenceStore.GetBlockSequence(seq)
   780  	if err != nil {
   781  		return nil, 0, err
   782  	}
   783  	header, err := push.sequenceStore.GetBlockHeaderByHash(seqdata.Hash)
   784  	if err != nil {
   785  		return nil, 0, err
   786  	}
   787  	return &types.HeaderSeq{Num: seq, Seq: seqdata, Header: header}, header.Size(), nil
   788  }
   789  
   790  // GetLastPushSeq Seq的合法值从0开始的,所以没有获取到或者获取失败都应该返回-1
   791  func (push *Push) getLastPushSeq(subscribe *types.PushSubscribeReq) int64 {
   792  	seqbytes, err := push.store.GetKey(calcLastPushSeqNumKey(subscribe.Name))
   793  	if seqbytes == nil || err != nil {
   794  		if err != dbm.ErrNotFoundInDb {
   795  			storeLog.Error("getLastPushSeq", "error", err)
   796  		}
   797  		return -1
   798  	}
   799  	n, err := decodeHeight(seqbytes)
   800  	if err != nil {
   801  		return -1
   802  	}
   803  	chainlog.Info("getLastPushSeq", "name", subscribe.Name,
   804  		"Contract:", subscribe.Contract, "num", n)
   805  
   806  	return n
   807  }
   808  
   809  func (push *Push) setLastPushSeq(name string, num int64) error {
   810  	return push.store.SetSync(calcLastPushSeqNumKey(name), types.Encode(&types.Int64{Data: num}))
   811  }