github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/private/private.go (about)

     1  package private
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  
    10  	"github.com/kisexp/xdchain/common"
    11  	http2 "github.com/kisexp/xdchain/common/http"
    12  	"github.com/kisexp/xdchain/core/types"
    13  	"github.com/kisexp/xdchain/log"
    14  	"github.com/kisexp/xdchain/private/engine"
    15  	"github.com/kisexp/xdchain/private/engine/constellation"
    16  	"github.com/kisexp/xdchain/private/engine/notinuse"
    17  	"github.com/kisexp/xdchain/private/engine/tessera"
    18  )
    19  
    20  var (
    21  	// global variable to be accessed by other packages
    22  	// singleton gateway to interact with private transaction manager
    23  	P                PrivateTransactionManager
    24  	isPrivacyEnabled = false
    25  )
    26  
    27  type Identifiable interface {
    28  	Name() string
    29  	HasFeature(f engine.PrivateTransactionManagerFeature) bool
    30  }
    31  
    32  // Interacting with Private Transaction Manager APIs
    33  type PrivateTransactionManager interface {
    34  	Identifiable
    35  
    36  	Send(data []byte, from string, to []string, extra *engine.ExtraMetadata) (string, []string, common.EncryptedPayloadHash, error)
    37  	StoreRaw(data []byte, from string) (common.EncryptedPayloadHash, error)
    38  	SendSignedTx(data common.EncryptedPayloadHash, to []string, extra *engine.ExtraMetadata) (string, []string, []byte, error)
    39  	// Returns nil payload if not found
    40  	Receive(data common.EncryptedPayloadHash) (string, []string, []byte, *engine.ExtraMetadata, error)
    41  	// Returns nil payload if not found
    42  	ReceiveRaw(data common.EncryptedPayloadHash) ([]byte, string, *engine.ExtraMetadata, error)
    43  	IsSender(txHash common.EncryptedPayloadHash) (bool, error)
    44  	GetParticipants(txHash common.EncryptedPayloadHash) ([]string, error)
    45  	GetMandatory(txHash common.EncryptedPayloadHash) ([]string, error)
    46  	EncryptPayload(data []byte, from string, to []string, extra *engine.ExtraMetadata) ([]byte, error)
    47  	DecryptPayload(payload common.DecryptRequest) ([]byte, *engine.ExtraMetadata, error)
    48  
    49  	Groups() ([]engine.PrivacyGroup, error)
    50  }
    51  
    52  // This loads any config specified via the legacy environment variable
    53  func GetLegacyEnvironmentConfig() (http2.Config, error) {
    54  	return FromEnvironmentOrNil("PRIVATE_CONFIG")
    55  }
    56  
    57  func FromEnvironmentOrNil(name string) (http2.Config, error) {
    58  	cfgPath := os.Getenv(name)
    59  	cfg, err := http2.FetchConfigOrIgnore(cfgPath)
    60  	if err != nil {
    61  		return http2.Config{}, err
    62  	}
    63  
    64  	return cfg, nil
    65  }
    66  
    67  func InitialiseConnection(cfg http2.Config) error {
    68  	var err error
    69  	P, err = NewPrivateTxManager(cfg)
    70  	return err
    71  }
    72  
    73  func IsQuorumPrivacyEnabled() bool {
    74  	return isPrivacyEnabled
    75  }
    76  
    77  func NewPrivateTxManager(cfg http2.Config) (PrivateTransactionManager, error) {
    78  
    79  	if cfg.ConnectionType == http2.NoConnection {
    80  		log.Info("Running with private transaction manager disabled - quorum private transactions will not be supported")
    81  		return &notinuse.PrivateTransactionManager{}, nil
    82  	}
    83  
    84  	client, err := http2.CreateClient(cfg)
    85  	if err != nil {
    86  		return nil, fmt.Errorf("unable to create connection to private tx manager due to: %s", err)
    87  	}
    88  
    89  	ptm, err := selectPrivateTxManager(client)
    90  	if err != nil {
    91  		return nil, fmt.Errorf("unable to connect to private tx manager due to: %s", err)
    92  	}
    93  
    94  	isPrivacyEnabled = true
    95  	return ptm, nil
    96  }
    97  
    98  // First call /upcheck to make sure the private tx manager is up
    99  // Then call /version to decide which private tx manager client implementation to be used
   100  func selectPrivateTxManager(client *engine.Client) (PrivateTransactionManager, error) {
   101  	res, err := client.Get("/upcheck")
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	if res.StatusCode != 200 {
   106  		return nil, engine.ErrPrivateTxManagerNotReady
   107  	}
   108  	res, err = client.Get("/version")
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	defer res.Body.Close()
   113  	version, err := ioutil.ReadAll(res.Body)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	var privateTxManager PrivateTransactionManager
   118  	defer func() {
   119  		log.Info("Target Private Tx Manager", "name", privateTxManager.Name(), "distributionVersion", string(version))
   120  	}()
   121  	if res.StatusCode != 200 {
   122  		// Constellation doesn't have /version endpoint
   123  		privateTxManager = constellation.New(client)
   124  	} else {
   125  		privateTxManager = tessera.New(client, []byte(tessera.RetrieveTesseraAPIVersion(client)))
   126  	}
   127  	return privateTxManager, nil
   128  }
   129  
   130  // Retrieve the private transaction that is associated with a privacy marker transaction
   131  func FetchPrivateTransaction(data []byte) (*types.Transaction, []string, *engine.ExtraMetadata, error) {
   132  	txHash := common.BytesToEncryptedPayloadHash(data)
   133  
   134  	_, managedParties, txData, metadata, err := P.Receive(txHash)
   135  	if err != nil {
   136  		return nil, nil, nil, err
   137  	}
   138  	if txData == nil {
   139  		return nil, nil, nil, nil
   140  	}
   141  
   142  	var tx types.Transaction
   143  	err = json.NewDecoder(bytes.NewReader(txData)).Decode(&tx)
   144  	if err != nil {
   145  		log.Trace("failed to deserialize private transaction", "err", err)
   146  		return nil, nil, nil, err
   147  	}
   148  
   149  	return &tx, managedParties, metadata, nil
   150  }