github.com/ConsenSys/Quorum@v20.10.0+incompatible/extension/backend.go (about)

     1  package extension
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"sync"
     9  
    10  	"github.com/ethereum/go-ethereum/accounts"
    11  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/core/types"
    14  	"github.com/ethereum/go-ethereum/ethclient"
    15  	"github.com/ethereum/go-ethereum/event"
    16  	"github.com/ethereum/go-ethereum/extension/extensionContracts"
    17  	"github.com/ethereum/go-ethereum/internal/ethapi"
    18  	"github.com/ethereum/go-ethereum/log"
    19  	"github.com/ethereum/go-ethereum/node"
    20  	"github.com/ethereum/go-ethereum/p2p"
    21  	"github.com/ethereum/go-ethereum/private"
    22  	"github.com/ethereum/go-ethereum/private/engine"
    23  	"github.com/ethereum/go-ethereum/rpc"
    24  )
    25  
    26  type PrivacyService struct {
    27  	ptm                      private.PrivateTransactionManager
    28  	stateFetcher             *StateFetcher
    29  	accountManager           *accounts.Manager
    30  	dataHandler              DataHandler
    31  	managementContractFacade ManagementContractFacade
    32  	extClient                Client
    33  	stopFeed                 event.Feed
    34  
    35  	mu               sync.Mutex
    36  	currentContracts map[common.Address]*ExtensionContract
    37  }
    38  
    39  var (
    40  	//default gas limit to use if not passed in sendTxArgs
    41  	defaultGasLimit = uint64(4712384)
    42  	//default gas price to use if not passed in sendTxArgs
    43  	defaultGasPrice = big.NewInt(0)
    44  
    45  	//Private participants must be specified for contract extension related transactions
    46  	errNotPrivate = errors.New("must specify private participants")
    47  )
    48  
    49  // to signal all watches when service is stopped
    50  type stopEvent struct {
    51  }
    52  
    53  func (service *PrivacyService) subscribeStopEvent() (chan stopEvent, event.Subscription) {
    54  	c := make(chan stopEvent)
    55  	s := service.stopFeed.Subscribe(c)
    56  	return c, s
    57  }
    58  
    59  func New(ptm private.PrivateTransactionManager, manager *accounts.Manager, handler DataHandler, fetcher *StateFetcher) (*PrivacyService, error) {
    60  	service := &PrivacyService{
    61  		currentContracts: make(map[common.Address]*ExtensionContract),
    62  		ptm:              ptm,
    63  		dataHandler:      handler,
    64  		stateFetcher:     fetcher,
    65  		accountManager:   manager,
    66  	}
    67  
    68  	var err error
    69  	service.currentContracts, err = service.dataHandler.Load()
    70  	if err != nil {
    71  		return nil, errors.New("could not load existing extension contracts: " + err.Error())
    72  	}
    73  
    74  	return service, nil
    75  }
    76  
    77  func (service *PrivacyService) initialise(node *node.Node) {
    78  	service.mu.Lock()
    79  	defer service.mu.Unlock()
    80  
    81  	rpcClient, err := node.Attach()
    82  	if err != nil {
    83  		panic("extension: could not connect to ethereum client rpc")
    84  	}
    85  
    86  	client := ethclient.NewClientWithPTM(rpcClient, service.ptm)
    87  	service.managementContractFacade = NewManagementContractFacade(client)
    88  	service.extClient = NewInProcessClient(client)
    89  
    90  	for _, f := range []func() error{
    91  		service.watchForNewContracts,       // watch for new extension contract creation event
    92  		service.watchForCancelledContracts, // watch for extension contract cancellation event
    93  		service.watchForCompletionEvents,   // watch for extension contract voting complete event
    94  	} {
    95  		if err := f(); err != nil {
    96  			log.Error("")
    97  		}
    98  	}
    99  
   100  }
   101  
   102  func (service *PrivacyService) watchForNewContracts() error {
   103  	incomingLogs, subscription, err := service.extClient.SubscribeToLogs(newExtensionQuery)
   104  
   105  	if err != nil {
   106  		return err
   107  	}
   108  
   109  	go func() {
   110  		stopChan, stopSubscription := service.subscribeStopEvent()
   111  		defer stopSubscription.Unsubscribe()
   112  		for {
   113  			select {
   114  			case err := <-subscription.Err():
   115  				log.Error("Contract extension watcher subscription error", "error", err)
   116  				break
   117  
   118  			case foundLog := <-incomingLogs:
   119  				service.mu.Lock()
   120  
   121  				tx, _ := service.extClient.TransactionByHash(foundLog.TxHash)
   122  				from, _ := types.QuorumPrivateTxSigner{}.Sender(tx)
   123  
   124  				newExtensionEvent, err := extensionContracts.UnpackNewExtensionCreatedLog(foundLog.Data)
   125  				if err != nil {
   126  					log.Error("Error unpacking extension creation log", "error", err)
   127  					log.Debug("Errored log", foundLog)
   128  					service.mu.Unlock()
   129  					continue
   130  				}
   131  
   132  				newContractExtension := ExtensionContract{
   133  					ContractExtended:          newExtensionEvent.ToExtend,
   134  					Initiator:                 from,
   135  					Recipient:                 newExtensionEvent.RecipientAddress,
   136  					RecipientPtmKey:           newExtensionEvent.RecipientPTMKey,
   137  					ManagementContractAddress: foundLog.Address,
   138  					CreationData:              tx.Data(),
   139  				}
   140  
   141  				service.currentContracts[foundLog.Address] = &newContractExtension
   142  				err = service.dataHandler.Save(service.currentContracts)
   143  				if err != nil {
   144  					log.Error("Error writing extension data to file", "error", err)
   145  					service.mu.Unlock()
   146  					continue
   147  				}
   148  				service.mu.Unlock()
   149  
   150  				// if party is sender then complete self voting
   151  				data := common.BytesToEncryptedPayloadHash(newContractExtension.CreationData)
   152  				isSender, _ := service.ptm.IsSender(data)
   153  
   154  				if isSender {
   155  					fetchedParties, err := service.ptm.GetParticipants(data)
   156  					if err != nil || len(fetchedParties) == 0 {
   157  						log.Error("Extension: unable to fetch all parties for extension management contract", "error", err)
   158  						continue
   159  					}
   160  					//Find the extension contract in order to interact with it
   161  					caller, _ := service.managementContractFacade.Caller(newContractExtension.ManagementContractAddress)
   162  					contractCreator, _ := caller.Creator(nil)
   163  
   164  					txArgs := ethapi.SendTxArgs{From: contractCreator, PrivateTxArgs: ethapi.PrivateTxArgs{PrivateFor: fetchedParties}}
   165  
   166  					extensionAPI := NewPrivateExtensionAPI(service)
   167  					_, err = extensionAPI.ApproveExtension(newContractExtension.ManagementContractAddress, true, txArgs)
   168  
   169  					if err != nil {
   170  						log.Error("Extension: initiator vote on management contract failed", "error", err)
   171  					}
   172  				}
   173  
   174  			case <-stopChan:
   175  				return
   176  			}
   177  		}
   178  	}()
   179  
   180  	return nil
   181  }
   182  
   183  func (service *PrivacyService) watchForCancelledContracts() error {
   184  	incomingLogs, subscription, err := service.extClient.SubscribeToLogs(finishedExtensionQuery)
   185  
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	go func() {
   191  		stopChan, stopSubscription := service.subscribeStopEvent()
   192  		defer stopSubscription.Unsubscribe()
   193  		for {
   194  			select {
   195  			case err := <-subscription.Err():
   196  				log.Error("Contract cancellation extension watcher subscription error", "error", err)
   197  				return
   198  			case l := <-incomingLogs:
   199  				service.mu.Lock()
   200  				if _, ok := service.currentContracts[l.Address]; ok {
   201  					delete(service.currentContracts, l.Address)
   202  					if err := service.dataHandler.Save(service.currentContracts); err != nil {
   203  						log.Error("Faile to store list of contracts being extended", "error", err)
   204  					}
   205  				}
   206  				service.mu.Unlock()
   207  			case <-stopChan:
   208  				return
   209  			}
   210  		}
   211  
   212  	}()
   213  
   214  	return nil
   215  }
   216  
   217  func (service *PrivacyService) watchForCompletionEvents() error {
   218  	incomingLogs, _, err := service.extClient.SubscribeToLogs(canPerformStateShareQuery)
   219  
   220  	if err != nil {
   221  		return err
   222  	}
   223  
   224  	go func() {
   225  		stopChan, stopSubscription := service.subscribeStopEvent()
   226  		defer stopSubscription.Unsubscribe()
   227  		for {
   228  			select {
   229  			case l := <-incomingLogs:
   230  				log.Debug("Extension: Received a completion event", "address", l.Address.Hex(), "blockNumber", l.BlockNumber)
   231  				service.mu.Lock()
   232  				func() {
   233  					defer func() {
   234  						service.mu.Unlock()
   235  					}()
   236  					extensionEntry, ok := service.currentContracts[l.Address]
   237  					if !ok {
   238  						// we didn't have this management contract, so ignore it
   239  						log.Debug("Extension: this node doesn't participate in the contract extender", "address", l.Address.Hex())
   240  						return
   241  					}
   242  
   243  					//Find the extension contract in order to interact with it
   244  					caller, err := service.managementContractFacade.Caller(l.Address)
   245  					if err != nil {
   246  						log.Error("service.managementContractFacade.Caller", "address", l.Address.Hex(), "error", err)
   247  						return
   248  					}
   249  					contractCreator, err := caller.Creator(nil)
   250  					if err != nil {
   251  						log.Error("[contract] caller.Creator", "error", err)
   252  						return
   253  					}
   254  					log.Debug("Extension: check if this node has the account that created the contract extender", "account", contractCreator)
   255  					if _, err := service.accountManager.Find(accounts.Account{Address: contractCreator}); err != nil {
   256  						log.Warn("Account used to sign extension contract no longer available", "account", contractCreator.Hex())
   257  						return
   258  					}
   259  
   260  					// fetch all the participants and send
   261  					payload := common.BytesToEncryptedPayloadHash(extensionEntry.CreationData)
   262  					fetchedParties, err := service.ptm.GetParticipants(payload)
   263  					if err != nil || len(fetchedParties) == 0 {
   264  						log.Error("Extension: Unable to fetch all parties for extension management contract", "error", err)
   265  						return
   266  					}
   267  					log.Debug("Extension: able to fetch all parties", "parties", fetchedParties)
   268  
   269  					txArgs, err := service.GenerateTransactOptions(ethapi.SendTxArgs{From: contractCreator, PrivateTxArgs: ethapi.PrivateTxArgs{PrivateFor: fetchedParties}})
   270  					if err != nil {
   271  						log.Error("service.accountManager.GenerateTransactOptions", "error", err, "contractCreator", contractCreator.Hex(), "privateFor", fetchedParties)
   272  						return
   273  					}
   274  
   275  					//we found the account, so we can send
   276  					contractToExtend, err := caller.ContractToExtend(nil)
   277  					if err != nil {
   278  						log.Error("[contract] caller.ContractToExtend", "error", err)
   279  						return
   280  					}
   281  					log.Debug("Extension: dump current state", "block", l.BlockHash, "contract", contractToExtend.Hex())
   282  					entireStateData, err := service.stateFetcher.GetAddressStateFromBlock(l.BlockHash, contractToExtend)
   283  					if err != nil {
   284  						log.Error("[state] service.stateFetcher.GetAddressStateFromBlock", "block", l.BlockHash.Hex(), "contract", contractToExtend.Hex(), "error", err)
   285  						return
   286  					}
   287  
   288  					log.Debug("Extension: send the state dump to the new recipient", "recipients", fetchedParties)
   289  
   290  					// PSV & PP changes
   291  					// send the new transaction with state dump to all participants
   292  					extraMetaData := engine.ExtraMetadata{PrivacyFlag: engine.PrivacyFlagStandardPrivate}
   293  					privacyMetaData, err := service.stateFetcher.GetPrivacyMetaData(l.BlockHash, contractToExtend)
   294  					if err != nil {
   295  						log.Error("[privacyMetaData] fetch err", "err", err)
   296  					} else {
   297  						extraMetaData.PrivacyFlag = privacyMetaData.PrivacyFlag
   298  						if privacyMetaData.PrivacyFlag == engine.PrivacyFlagStateValidation {
   299  							storageRoot, err := service.stateFetcher.GetStorageRoot(l.BlockHash, contractToExtend)
   300  							if err != nil {
   301  								log.Error("[storageRoot] fetch err", "err", err)
   302  							}
   303  							extraMetaData.ACMerkleRoot = storageRoot
   304  						}
   305  					}
   306  					hashOfStateData, err := service.ptm.Send(entireStateData, "", fetchedParties, &extraMetaData)
   307  
   308  					if err != nil {
   309  						log.Error("[ptm] service.ptm.Send", "stateDataInHex", hex.EncodeToString(entireStateData[:]), "recipients", fetchedParties, "error", err)
   310  						return
   311  					}
   312  					hashofStateDataBase64 := hashOfStateData.ToBase64()
   313  
   314  					transactor, err := service.managementContractFacade.Transactor(l.Address)
   315  					if err != nil {
   316  						log.Error("service.managementContractFacade.Transactor", "address", l.Address.Hex(), "error", err)
   317  						return
   318  					}
   319  					log.Debug("Extension: store the encrypted payload hash of dump state", "contract", l.Address.Hex())
   320  					if tx, err := transactor.SetSharedStateHash(txArgs, hashofStateDataBase64); err != nil {
   321  						log.Error("[contract] transactor.SetSharedStateHash", "error", err, "hashOfStateInBase64", hashofStateDataBase64)
   322  					} else {
   323  						log.Debug("Extension: transaction carrying shared state", "txhash", tx.Hash(), "private", tx.IsPrivate())
   324  					}
   325  				}()
   326  			case <-stopChan:
   327  				return
   328  			}
   329  		}
   330  
   331  	}()
   332  	return nil
   333  }
   334  
   335  // node.Service interface methods:
   336  func (service *PrivacyService) Protocols() []p2p.Protocol {
   337  	return []p2p.Protocol{}
   338  }
   339  
   340  func (service *PrivacyService) APIs() []rpc.API {
   341  	return []rpc.API{
   342  		{
   343  			Namespace: "quorumExtension",
   344  			Version:   "1.0",
   345  			Service:   NewPrivateExtensionAPI(service),
   346  			Public:    true,
   347  		},
   348  	}
   349  }
   350  
   351  func (service *PrivacyService) Start(p2pServer *p2p.Server) error {
   352  	log.Debug("extension service: starting")
   353  	return nil
   354  }
   355  
   356  func (service *PrivacyService) Stop() error {
   357  	log.Info("extension service: stopping")
   358  	service.stopFeed.Send(stopEvent{})
   359  	log.Info("extension service: stopped")
   360  	return nil
   361  }
   362  
   363  func (service *PrivacyService) GenerateTransactOptions(txa ethapi.SendTxArgs) (*bind.TransactOpts, error) {
   364  	if txa.PrivateFor == nil {
   365  		return nil, errNotPrivate
   366  	}
   367  	from := accounts.Account{Address: txa.From}
   368  	wallet, err := service.accountManager.Find(from)
   369  
   370  	if err != nil {
   371  		return nil, fmt.Errorf("no wallet found for account %s", txa.From.String())
   372  	}
   373  
   374  	//Find the account we plan to send the transaction from
   375  
   376  	txArgs := bind.NewWalletTransactor(wallet, from)
   377  	txArgs.PrivateFrom = txa.PrivateFrom
   378  	txArgs.PrivateFor = txa.PrivateFor
   379  	txArgs.GasLimit = defaultGasLimit
   380  	txArgs.GasPrice = defaultGasPrice
   381  	if txa.GasPrice != nil {
   382  		txArgs.GasPrice = txa.GasPrice.ToInt()
   383  	}
   384  	if txa.Gas != nil {
   385  		txArgs.GasLimit = uint64(*txa.Gas)
   386  	}
   387  	return txArgs, nil
   388  }
   389  
   390  // returns the participant list for a given private contract
   391  func (service *PrivacyService) GetAllParticipants(blockHash common.Hash, address common.Address) ([]string, error) {
   392  	privacyMetaData, err := service.stateFetcher.GetPrivacyMetaData(blockHash, address)
   393  	if err != nil {
   394  		return nil, err
   395  	}
   396  	if privacyMetaData.PrivacyFlag.IsStandardPrivate() {
   397  		return nil, nil
   398  	}
   399  
   400  	participants, err := service.ptm.GetParticipants(privacyMetaData.CreationTxHash)
   401  	if err != nil {
   402  		return nil, err
   403  	}
   404  	return participants, nil
   405  }
   406  
   407  // check if the node had created the contract
   408  func (service *PrivacyService) CheckIfContractCreator(blockHash common.Hash, address common.Address) bool {
   409  	privacyMetaData, err := service.stateFetcher.GetPrivacyMetaData(blockHash, address)
   410  	if err != nil {
   411  		return true
   412  	}
   413  
   414  	isCreator, err := service.ptm.IsSender(privacyMetaData.CreationTxHash)
   415  	if err != nil {
   416  		return false
   417  	}
   418  
   419  	return isCreator
   420  }