github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/infura/endblocker.go (about)

     1  package infura
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     8  )
     9  
    10  func EndBlocker(ctx sdk.Context, k Keeper) {
    11  	k.stream.logger.Debug("infura EndBlocker begin")
    12  	if !k.stream.enable {
    13  		k.stream.logger.Debug("infura engine is not enable")
    14  		return
    15  	}
    16  	// prepare task data
    17  	sc := StreamContext{
    18  		blockHeight: ctx.BlockHeight(),
    19  		stream:      k.stream,
    20  		task:        newTask(ctx.BlockHeight(), k.stream.cache),
    21  	}
    22  
    23  	// cache queue
    24  	if k.stream.cacheQueue != nil {
    25  		k.stream.logger.Debug(fmt.Sprintf("cache queue: len:%d, cap:%d, enqueue:%d",
    26  			len(k.stream.cacheQueue.queue), cap(k.stream.cacheQueue.queue), sc.blockHeight))
    27  		// block if cache queue is full
    28  		k.stream.cacheQueue.Enqueue(sc)
    29  		k.metric.CacheSize.Set(float64(len(k.stream.cacheQueue.queue)))
    30  		return
    31  	}
    32  
    33  	execute(sc)
    34  	k.stream.logger.Debug("infura EndBlocker end")
    35  }
    36  
    37  func prepareStreamTask(blockHeight int64, ctx StreamContext) (taskConst TaskConst, err error) {
    38  	if ctx.task != nil && ctx.task.Height > blockHeight {
    39  		return TaskPhase1NextActionJumpNextBlock, nil
    40  	}
    41  
    42  	// fetch distribute lock
    43  	locked, err := ctx.stream.scheduler.FetchDistLock(
    44  		distributeLock, ctx.stream.scheduler.GetLockerID(), taskTimeout)
    45  
    46  	if !locked || err != nil {
    47  		return TaskPhase1NextActionRestart, err
    48  	}
    49  
    50  	state := ctx.stream.scheduler.GetDistState(latestTaskKey)
    51  	if len(state) > 0 {
    52  		ctx.task, err = parseTaskFromJSON(state)
    53  		if err != nil {
    54  			return releaseLockWithStatus(ctx.stream, TaskPhase1NextActionRestart, err)
    55  		}
    56  		if ctx.task.Height > blockHeight {
    57  			return releaseLockWithStatus(ctx.stream, TaskPhase1NextActionJumpNextBlock, nil)
    58  		}
    59  		if ctx.task.Height == blockHeight {
    60  			if ctx.task.GetStatus() == TaskStatusSuccess {
    61  				return releaseLockWithStatus(ctx.stream, TaskPhase1NextActionJumpNextBlock, nil)
    62  			}
    63  			return TaskPhase1NextActionReturnTask, nil
    64  		}
    65  		if ctx.task.Height+1 == blockHeight {
    66  			return TaskPhase1NextActionNewTask, nil
    67  		}
    68  		return releaseLockWithStatus(ctx.stream, TaskPhase1NextActionUnknown,
    69  			fmt.Errorf("error: EndBlock-(%d) should never run into here, distrLatestBlock: %+v",
    70  				blockHeight, ctx.task))
    71  	}
    72  	return TaskPhase1NextActionNewTask, nil
    73  
    74  }
    75  
    76  func releaseLockWithStatus(s *Stream, taskConst TaskConst, err error) (TaskConst, error) {
    77  	rSuccess, rErr := s.scheduler.ReleaseDistLock(distributeLock, s.scheduler.GetLockerID())
    78  	if !rSuccess || rErr != nil {
    79  		return TaskPhase1NextActionRestart, rErr
    80  	}
    81  	return taskConst, err
    82  }
    83  
    84  func executeStreamTask(s *Stream, task *Task) (taskConst TaskConst, err error) {
    85  	done := s.engine.Write(task.Data)
    86  	task.Done = done
    87  	stateStr := task.toJSON()
    88  	success, err := s.scheduler.UnlockDistLockWithState(
    89  		distributeLock, s.scheduler.GetLockerID(), latestTaskKey, stateStr)
    90  	if success && err == nil {
    91  		if task.GetStatus() != TaskStatusSuccess {
    92  			return TaskPhase2NextActionRestart, nil
    93  		}
    94  		return TaskPhase2NextActionJumpNextBlock, nil
    95  	}
    96  
    97  	return TaskPhase2NextActionRestart, err
    98  
    99  }
   100  
   101  func execute(ctx StreamContext) {
   102  	for {
   103  		p1Status, p1err := prepareStreamTask(ctx.blockHeight, ctx)
   104  		if p1err != nil {
   105  			ctx.stream.logger.Error(p1err.Error())
   106  		}
   107  		ctx.stream.logger.Debug(fmt.Sprintf("P1Status: %s", TaskConstDesc[p1Status]))
   108  		switch p1Status {
   109  		case TaskPhase1NextActionRestart:
   110  			time.Sleep(1500 * time.Millisecond)
   111  			continue
   112  		case TaskPhase1NextActionUnknown:
   113  			err := fmt.Errorf("infura unexpected exception, %+v", p1err)
   114  			panic(err)
   115  		case TaskPhase1NextActionJumpNextBlock:
   116  			return
   117  		default:
   118  			p2Status, p2err := executeStreamTask(ctx.stream, ctx.task)
   119  			if p2err != nil {
   120  				ctx.stream.logger.Error(p2err.Error())
   121  			}
   122  
   123  			ctx.stream.logger.Debug(fmt.Sprintf("P2Status: %s", TaskConstDesc[p2Status]))
   124  
   125  			switch p2Status {
   126  			case TaskPhase2NextActionRestart:
   127  				time.Sleep(5000 * time.Millisecond)
   128  			case TaskPhase2NextActionJumpNextBlock:
   129  				return
   130  			}
   131  		}
   132  	}
   133  }