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 }