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 }