state_transition_pmh.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package core
  2. import (
  3. "fmt"
  4. "github.com/ethereum/go-ethereum/common"
  5. "github.com/ethereum/go-ethereum/core/state"
  6. "github.com/ethereum/go-ethereum/core/types"
  7. "github.com/ethereum/go-ethereum/log"
  8. "github.com/ethereum/go-ethereum/private/engine"
  9. )
  10. type pmcStateTransitionAPI interface {
  11. SetTxPrivacyMetadata(pm *types.PrivacyMetadata)
  12. IsPrivacyEnhancementsEnabled() bool
  13. RevertToSnapshot(int)
  14. GetStatePrivacyMetadata(addr common.Address) (*state.PrivacyMetadata, error)
  15. CalculateMerkleRoot() (common.Hash, error)
  16. AffectedContracts() []common.Address
  17. }
  18. func newPMH(st pmcStateTransitionAPI) *privateMessageHandler {
  19. return &privateMessageHandler{stAPI: st}
  20. }
  21. type privateMessageHandler struct {
  22. stAPI pmcStateTransitionAPI
  23. hasPrivatePayload bool
  24. snapshot int
  25. receivedPrivacyMetadata *engine.ExtraMetadata
  26. eph common.EncryptedPayloadHash
  27. }
  28. func (pmh *privateMessageHandler) mustVerify() bool {
  29. return pmh.hasPrivatePayload && pmh.receivedPrivacyMetadata != nil && pmh.stAPI.IsPrivacyEnhancementsEnabled()
  30. }
  31. // checks the privacy metadata in the state transition context
  32. // returns vmError if there is an error in the EVM execution
  33. // returns consensusErr if there is an error in the consensus execution
  34. func (pmh *privateMessageHandler) prepare() (vmError, consensusErr error) {
  35. if pmh.receivedPrivacyMetadata != nil {
  36. if !pmh.stAPI.IsPrivacyEnhancementsEnabled() && pmh.receivedPrivacyMetadata.PrivacyFlag.IsNotStandardPrivate() {
  37. // This situation is only possible if the current node has been upgraded (both quorum and tessera) yet the
  38. // node did not apply the privacyEnhancementsBlock configuration (with a network agreed block height).
  39. // Since this would be considered node misconfiguration the behavior should be changed to return an error
  40. // which would then cause the node not to apply the block (and potentially get stuck and not be able to
  41. // continue to apply new blocks). The resolution should then be to revert to an appropriate block height and
  42. // run geth init with the network agreed privacyEnhancementsBlock.
  43. // The prepare method signature has been changed to allow returning the relevant error.
  44. return ErrPrivacyEnhancedReceivedWhenDisabled, fmt.Errorf("Privacy enhanced transaction received while privacy enhancements are disabled."+
  45. " Please check your node configuration. EPH=%s", pmh.eph.ToBase64())
  46. }
  47. if pmh.receivedPrivacyMetadata.PrivacyFlag == engine.PrivacyFlagStateValidation && common.EmptyHash(pmh.receivedPrivacyMetadata.ACMerkleRoot) {
  48. log.Error(ErrPrivacyMetadataInvalidMerkleRoot.Error())
  49. return ErrPrivacyMetadataInvalidMerkleRoot, nil
  50. }
  51. privMetadata := types.NewTxPrivacyMetadata(pmh.receivedPrivacyMetadata.PrivacyFlag)
  52. pmh.stAPI.SetTxPrivacyMetadata(privMetadata)
  53. }
  54. return nil, nil
  55. }
  56. //If the list of affected CA Transactions by the time evm executes is different from the list of affected contract transactions returned from Tessera
  57. //an Error should be thrown and the state should not be updated
  58. //This validation is to prevent cases where the list of affected contract will have changed by the time the evm actually executes transaction
  59. // failed = true will make sure receipt is marked as "failure"
  60. // return error will crash the node and only use when that's the case
  61. func (pmh *privateMessageHandler) verify(vmerr error) (bool, error) {
  62. // convenient function to return error. It has the same signature as the main function
  63. returnErrorFunc := func(anError error, logMsg string, ctx ...interface{}) (exitEarly bool, err error) {
  64. if logMsg != "" {
  65. log.Debug(logMsg, ctx...)
  66. }
  67. pmh.stAPI.RevertToSnapshot(pmh.snapshot)
  68. exitEarly = true
  69. if anError != nil {
  70. err = fmt.Errorf("vmerr=%s, err=%s", vmerr, anError)
  71. }
  72. return
  73. }
  74. actualACAddresses := pmh.stAPI.AffectedContracts()
  75. log.Trace("Verify hashes of affected contracts", "expectedHashes", pmh.receivedPrivacyMetadata.ACHashes, "numberOfAffectedAddresses", len(actualACAddresses))
  76. privacyFlag := pmh.receivedPrivacyMetadata.PrivacyFlag
  77. for _, addr := range actualACAddresses {
  78. // GetPrivacyMetadata is invoked on the privateState (as the tx is private) and it returns:
  79. // 1. public contacts: privacyMetadata = nil, err = nil
  80. // 2. private contracts of type:
  81. // 2.1. StandardPrivate: privacyMetadata = nil, err = "The provided contract does not have privacy metadata"
  82. // 2.2. PartyProtection/PSV: privacyMetadata = <data>, err = nil
  83. actualPrivacyMetadata, err := pmh.stAPI.GetStatePrivacyMetadata(addr)
  84. //when privacyMetadata should have been recovered but wasnt (includes non-party)
  85. //non party will only be caught here if sender provides privacyFlag
  86. if err != nil && privacyFlag.IsNotStandardPrivate() {
  87. return returnErrorFunc(nil, "Unable to find PrivacyMetadata for affected contract", "err", err, "addr", addr.Hex())
  88. }
  89. log.Trace("Privacy metadata", "affectedAddress", addr.Hex(), "metadata", actualPrivacyMetadata)
  90. // both public and standard private contracts will be nil and can be skipped in acoth check
  91. // public contracts - evm error for write, no error for reads
  92. // standard private - only error if privacyFlag sent with tx or if no flag sent but other affecteds have privacyFlag
  93. if actualPrivacyMetadata == nil {
  94. continue
  95. }
  96. // Check that the affected contracts privacy flag matches the transaction privacy flag.
  97. // I know that this is also checked by tessera, but it only checks for non standard private transactions.
  98. if actualPrivacyMetadata.PrivacyFlag != pmh.receivedPrivacyMetadata.PrivacyFlag {
  99. return returnErrorFunc(nil, "Mismatched privacy flags",
  100. "affectedContract.Address", addr.Hex(),
  101. "affectedContract.PrivacyFlag", actualPrivacyMetadata.PrivacyFlag,
  102. "received.PrivacyFlag", pmh.receivedPrivacyMetadata.PrivacyFlag)
  103. }
  104. // acoth check - case where node isn't privy to one of actual affecteds
  105. if pmh.receivedPrivacyMetadata.ACHashes.NotExist(actualPrivacyMetadata.CreationTxHash) {
  106. return returnErrorFunc(nil, "Participation check failed",
  107. "affectedContractAddress", addr.Hex(),
  108. "missingCreationTxHash", actualPrivacyMetadata.CreationTxHash.Hex())
  109. }
  110. }
  111. // check the psv merkle root comparison - for both creation and msg calls
  112. if !common.EmptyHash(pmh.receivedPrivacyMetadata.ACMerkleRoot) {
  113. log.Trace("Verify merkle root", "merkleRoot", pmh.receivedPrivacyMetadata.ACMerkleRoot)
  114. actualACMerkleRoot, err := pmh.stAPI.CalculateMerkleRoot()
  115. if err != nil {
  116. return returnErrorFunc(err, "")
  117. }
  118. if actualACMerkleRoot != pmh.receivedPrivacyMetadata.ACMerkleRoot {
  119. return returnErrorFunc(nil, "Merkle Root check failed", "actual", actualACMerkleRoot,
  120. "expect", pmh.receivedPrivacyMetadata.ACMerkleRoot)
  121. }
  122. }
  123. return false, nil
  124. }