github.com/Night-mk/quorum@v21.1.0+incompatible/extension/backend.go (about)

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