backend.go 16 KB

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