github.com/RobustRoundRobin/quorum@v20.10.0+incompatible/private/private.go (about)

     1  package private
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/log"
    14  	"github.com/ethereum/go-ethereum/private/engine"
    15  	"github.com/ethereum/go-ethereum/private/engine/constellation"
    16  	"github.com/ethereum/go-ethereum/private/engine/notinuse"
    17  	"github.com/ethereum/go-ethereum/private/engine/tessera"
    18  	"github.com/tv42/httpunix"
    19  )
    20  
    21  var (
    22  	// global variable to be accessed by other packages
    23  	// singleton gateway to interact with private transaction manager
    24  	P = FromEnvironmentOrNil("PRIVATE_CONFIG")
    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) (common.EncryptedPayloadHash, error)
    37  	StoreRaw(data []byte, from string) (common.EncryptedPayloadHash, error)
    38  	SendSignedTx(data common.EncryptedPayloadHash, to []string, extra *engine.ExtraMetadata) ([]byte, error)
    39  	// Returns nil payload if not found
    40  	Receive(data common.EncryptedPayloadHash) ([]byte, *engine.ExtraMetadata, error)
    41  	// Returns nil payload if not found
    42  	ReceiveRaw(data common.EncryptedPayloadHash) ([]byte, *engine.ExtraMetadata, error)
    43  	IsSender(txHash common.EncryptedPayloadHash) (bool, error)
    44  	GetParticipants(txHash common.EncryptedPayloadHash) ([]string, error)
    45  	EncryptPayload(data []byte, from string, to []string, extra *engine.ExtraMetadata) ([]byte, error)
    46  	DecryptPayload(payload common.DecryptRequest) ([]byte, *engine.ExtraMetadata, error)
    47  }
    48  
    49  func FromEnvironmentOrNil(name string) PrivateTransactionManager {
    50  	cfgPath := os.Getenv(name)
    51  	if cfgPath == "" {
    52  		return nil
    53  	}
    54  	if strings.EqualFold(cfgPath, "ignore") {
    55  		return &notinuse.PrivateTransactionManager{}
    56  	}
    57  	return MustNewPrivateTxManager(cfgPath)
    58  }
    59  
    60  func MustNewPrivateTxManager(cfgPath string) PrivateTransactionManager {
    61  	info, err := os.Lstat(cfgPath)
    62  	if err != nil {
    63  		panic(fmt.Sprintf("unable to read %s due to %s", cfgPath, err))
    64  	}
    65  	// We accept either the socket or a configuration file that points to
    66  	// a socket.
    67  	socketPath := cfgPath
    68  	isSocket := info.Mode()&os.ModeSocket != 0
    69  	if !isSocket {
    70  		cfg, err := engine.LoadConfig(cfgPath)
    71  		if err != nil {
    72  			panic(fmt.Sprintf("unable to load configuration file for private transaction manager from %s due to %s", cfgPath, err))
    73  		}
    74  		socketPath = filepath.Join(cfg.WorkDir, cfg.Socket)
    75  	}
    76  
    77  	client := &engine.Client{
    78  		HttpClient: &http.Client{
    79  			Transport: unixTransport(socketPath),
    80  		},
    81  		BaseURL: "http+unix://c",
    82  	}
    83  	ptm, err := selectPrivateTxManager(client)
    84  	if err != nil {
    85  		panic(fmt.Sprintf("unable to connect to private tx manager using %s due to %s", socketPath, err))
    86  	}
    87  	return ptm
    88  }
    89  
    90  func unixTransport(socketPath string) *httpunix.Transport {
    91  	t := &httpunix.Transport{
    92  		DialTimeout:           1 * time.Second,
    93  		RequestTimeout:        5 * time.Second,
    94  		ResponseHeaderTimeout: 5 * time.Second,
    95  	}
    96  	t.RegisterLocation("c", socketPath)
    97  	return t
    98  }
    99  
   100  // First call /upcheck to make sure the private tx manager is up
   101  // Then call /version to decide which private tx manager client implementation to be used
   102  func selectPrivateTxManager(client *engine.Client) (PrivateTransactionManager, error) {
   103  	res, err := client.Get("/upcheck")
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	if res.StatusCode != 200 {
   108  		return nil, engine.ErrPrivateTxManagerNotReady
   109  	}
   110  	res, err = client.Get("/version")
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	defer res.Body.Close()
   115  	version, err := ioutil.ReadAll(res.Body)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	var privateTxManager PrivateTransactionManager
   120  	defer func() {
   121  		log.Info("Target Private Tx Manager", "name", privateTxManager.Name(), "distributionVersion", version)
   122  	}()
   123  	if res.StatusCode != 200 {
   124  		// Constellation doesn't have /version endpoint
   125  		privateTxManager = constellation.New(client)
   126  	} else {
   127  		privateTxManager = tessera.New(client, []byte(tessera.RetrieveTesseraAPIVersion(client)))
   128  	}
   129  	return privateTxManager, nil
   130  }