github.com/turingchain2020/turingchain@v1.1.21/client/api/api.go (about)

     1  //这个包提供了平行链和主链的统一的访问接口
     2  
     3  package api
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"sync/atomic"
     9  
    10  	"github.com/turingchain2020/turingchain/client"
    11  	"github.com/turingchain2020/turingchain/queue"
    12  	"github.com/turingchain2020/turingchain/types"
    13  	"google.golang.org/grpc"
    14  	"google.golang.org/grpc/codes"
    15  )
    16  
    17  /*
    18  平行链可以访问的有两条链:
    19  1. 通过 client.QueueProtocolAPI 事件访问 平行链本身
    20  2. 通过 grpc 接口访问主链
    21  
    22  通过 client.QueueProtocolAPI 和 grpc 都可能会产生 网络错误,或者超时的问题
    23  这个时候,区块做异常处理的时候需要做一些特殊处理
    24  
    25  接口函数:
    26  1. GetBlockByHash
    27  2. GetLastBlockHash
    28  3. GetRandNum
    29  */
    30  
    31  //ErrAPIEnv api的执行环境出问题,区块执行的时候,遇到这一个的错误需要retry
    32  var errAPIEnv = errors.New("ErrAPIEnv")
    33  
    34  //ExecutorAPI 提供给执行器使用的接口
    35  //因为合约是主链和平行链通用的,所以,主链和平行链都可以调用这套接口
    36  type ExecutorAPI interface {
    37  	GetBlockByHashes(param *types.ReqHashes) (*types.BlockDetails, error)
    38  	GetRandNum(param *types.ReqRandHash) ([]byte, error)
    39  	QueryTx(param *types.ReqHash) (*types.TransactionDetail, error)
    40  	IsErr() bool
    41  }
    42  
    43  type mainChainAPI struct {
    44  	api     client.QueueProtocolAPI
    45  	errflag int32
    46  }
    47  
    48  //New 新建接口
    49  func New(api client.QueueProtocolAPI, grpcClient types.TuringchainClient) ExecutorAPI {
    50  	types.AssertConfig(api)
    51  	types := api.GetConfig()
    52  	if types.IsPara() {
    53  		return newParaChainAPI(api, grpcClient)
    54  	}
    55  	return &mainChainAPI{api: api}
    56  }
    57  
    58  func (api *mainChainAPI) QueryTx(param *types.ReqHash) (*types.TransactionDetail, error) {
    59  	data, err := api.api.QueryTx(param)
    60  	return data, seterr(err, &api.errflag)
    61  }
    62  
    63  func (api *mainChainAPI) IsErr() bool {
    64  	return atomic.LoadInt32(&api.errflag) == 1
    65  }
    66  
    67  func (api *mainChainAPI) GetRandNum(param *types.ReqRandHash) ([]byte, error) {
    68  	msg, err := api.api.Query(param.ExecName, "RandNumHash", param)
    69  	if err != nil {
    70  		return nil, seterr(err, &api.errflag)
    71  	}
    72  	reply, ok := msg.(*types.ReplyHash)
    73  	if !ok {
    74  		return nil, types.ErrTypeAsset
    75  	}
    76  	return reply.Hash, nil
    77  }
    78  
    79  func (api *mainChainAPI) GetBlockByHashes(param *types.ReqHashes) (*types.BlockDetails, error) {
    80  	data, err := api.api.GetBlockByHashes(param)
    81  	return data, seterr(err, &api.errflag)
    82  }
    83  
    84  type paraChainAPI struct {
    85  	api        client.QueueProtocolAPI
    86  	grpcClient types.TuringchainClient
    87  	errflag    int32
    88  }
    89  
    90  func newParaChainAPI(api client.QueueProtocolAPI, grpcClient types.TuringchainClient) ExecutorAPI {
    91  	return &paraChainAPI{api: api, grpcClient: grpcClient}
    92  }
    93  
    94  func (api *paraChainAPI) IsErr() bool {
    95  	return atomic.LoadInt32(&api.errflag) == 1
    96  }
    97  
    98  func (api *paraChainAPI) QueryTx(param *types.ReqHash) (*types.TransactionDetail, error) {
    99  	data, err := api.grpcClient.QueryTransaction(context.Background(), param)
   100  	if err != nil {
   101  		err = errAPIEnv
   102  	}
   103  	return data, seterr(err, &api.errflag)
   104  }
   105  
   106  func (api *paraChainAPI) GetRandNum(param *types.ReqRandHash) ([]byte, error) {
   107  	reply, err := api.grpcClient.QueryRandNum(context.Background(), param)
   108  	if err != nil {
   109  		err = errAPIEnv
   110  		return nil, seterr(err, &api.errflag)
   111  	}
   112  	return reply.Hash, nil
   113  }
   114  
   115  func (api *paraChainAPI) GetBlockByHashes(param *types.ReqHashes) (*types.BlockDetails, error) {
   116  	data, err := api.grpcClient.GetBlockByHashes(context.Background(), param)
   117  	if err != nil {
   118  		err = errAPIEnv
   119  	}
   120  	return data, seterr(err, &api.errflag)
   121  }
   122  
   123  func seterr(err error, flag *int32) error {
   124  	if IsGrpcError(err) || IsQueueError(err) {
   125  		atomic.StoreInt32(flag, 1)
   126  	}
   127  	return err
   128  }
   129  
   130  //IsGrpcError 判断系统api 错误,还是 rpc 本身的错误
   131  func IsGrpcError(err error) bool {
   132  	if err == nil {
   133  		return false
   134  	}
   135  	if err == errAPIEnv {
   136  		return true
   137  	}
   138  	if grpc.Code(err) == codes.Unknown {
   139  		return false
   140  	}
   141  	return true
   142  }
   143  
   144  //IsQueueError 是否是队列错误
   145  func IsQueueError(err error) bool {
   146  	if err == nil {
   147  		return false
   148  	}
   149  	if err == errAPIEnv {
   150  		return true
   151  	}
   152  	if err == queue.ErrQueueTimeout ||
   153  		err == queue.ErrQueueChannelFull ||
   154  		err == queue.ErrIsQueueClosed {
   155  		return true
   156  	}
   157  	return false
   158  }
   159  
   160  //IsFatalError 是否是必须停止执行的系统错误
   161  func IsFatalError(err error) bool {
   162  	if err == nil {
   163  		return false
   164  	}
   165  	if err == errAPIEnv {
   166  		return true
   167  	}
   168  	if err == types.ErrConsensusHashErr {
   169  		return true
   170  	}
   171  	return false
   172  }
   173  
   174  //IsAPIEnvError 是否是api执行环境的错误
   175  func IsAPIEnvError(err error) bool {
   176  	return IsGrpcError(err) || IsQueueError(err) || IsFatalError(err)
   177  }