github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/pkg/gateway/commit/finder.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  // Package commit provides an implementation for finding transaction commit status that is specific to the Gateway
     8  // embedded within a peer.
     9  package commit
    10  
    11  import (
    12  	"context"
    13  
    14  	"github.com/hyperledger/fabric-protos-go/peer"
    15  
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  type Status struct {
    20  	BlockNumber   uint64
    21  	TransactionID string
    22  	Code          peer.TxValidationCode
    23  }
    24  
    25  // QueryProvider provides status of previously committed transactions on a given channel. An error is returned if the
    26  // transaction is not present in the ledger.
    27  type QueryProvider interface {
    28  	TransactionStatus(channelName string, transactionID string) (peer.TxValidationCode, uint64, error)
    29  }
    30  
    31  // Finder is used to obtain transaction status.
    32  type Finder struct {
    33  	query    QueryProvider
    34  	notifier *Notifier
    35  }
    36  
    37  func NewFinder(query QueryProvider, notifier *Notifier) *Finder {
    38  	return &Finder{
    39  		query:    query,
    40  		notifier: notifier,
    41  	}
    42  }
    43  
    44  // TransactionStatus provides status of a specified transaction on a given channel. If the transaction has already
    45  // committed, the status is returned immediately; otherwise this call blocks waiting for the transaction to be
    46  // committed or the context to be cancelled.
    47  func (finder *Finder) TransactionStatus(ctx context.Context, channelName string, transactionID string) (*Status, error) {
    48  	// Set up notifier first to ensure no commit missed after completing query
    49  	notifyDone := make(chan struct{})
    50  	defer close(notifyDone)
    51  	statusReceive, err := finder.notifier.notifyStatus(notifyDone, channelName, transactionID)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	if code, blockNumber, err := finder.query.TransactionStatus(channelName, transactionID); err == nil {
    57  		status := &Status{
    58  			BlockNumber:   blockNumber,
    59  			TransactionID: transactionID,
    60  			Code:          code,
    61  		}
    62  		return status, nil
    63  	}
    64  
    65  	select {
    66  	case <-ctx.Done():
    67  		return nil, ctx.Err()
    68  	case status, ok := <-statusReceive:
    69  		if !ok {
    70  			return nil, errors.New("unexpected close of commit notification channel")
    71  		}
    72  		return status, nil
    73  	}
    74  }