package privacyExtension import ( "bytes" "encoding/json" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/mps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" extension "github.com/ethereum/go-ethereum/extension/extensionContracts" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/private" ) var DefaultExtensionHandler *ExtensionHandler type ExtensionHandler struct { ptm private.PrivateTransactionManager psmr mps.PrivateStateMetadataResolver isMultitenant bool } func Init() { DefaultExtensionHandler = NewExtensionHandler(private.P) } func NewExtensionHandler(transactionManager private.PrivateTransactionManager) *ExtensionHandler { return &ExtensionHandler{ptm: transactionManager} } func (handler *ExtensionHandler) SupportMultitenancy(b bool) { handler.isMultitenant = b } func (handler *ExtensionHandler) SetPSMR(psmr mps.PrivateStateMetadataResolver) { handler.psmr = psmr } func (handler *ExtensionHandler) CheckExtensionAndSetPrivateState(txLogs []*types.Log, privateState *state.StateDB, psi types.PrivateStateIdentifier) { extraMetaDataUpdated := false for _, txLog := range txLogs { if !logContainsExtensionTopic(txLog) { continue } //this is a direct state share address, hash, uuid, err := extension.UnpackStateSharedLog(txLog.Data) if err != nil { continue } // check if state exists for the extension address. If yes then skip // processing if privateState.GetCode(address) != nil { if extraMetaDataUpdated { continue } // check the privacy flag of the contract. if its other than // 0 then need to update the privacy metadata for the contract //TODO: validate the old and new parties to ensure that all old parties are there setPrivacyMetadata(privateState, address, hash) if handler.isMultitenant { setManagedParties(handler.ptm, privateState, address, hash) } extraMetaDataUpdated = true } else { managedParties, accounts, privacyMetaData, found := handler.FetchStateData(txLog.Address, hash, uuid, psi) if !found { continue } if !handler.isMultitenant { managedParties = nil } if !validateAccountsExist([]common.Address{address}, accounts) { log.Error("Account mismatch", "expected", address, "found", accounts) continue } snapshotId := privateState.Snapshot() if success := setState(privateState, accounts, privacyMetaData, managedParties); !success { privateState.RevertToSnapshot(snapshotId) } } } } func (handler *ExtensionHandler) FetchStateData(address common.Address, hash string, uuid string, psi types.PrivateStateIdentifier) ([]string, map[string]extension.AccountWithMetadata, *state.PrivacyMetadata, bool) { if uuidIsSentByUs := handler.UuidIsOwn(address, uuid, psi); !uuidIsSentByUs { return nil, nil, nil, false } managedParties, stateData, privacyMetaData, ok := handler.FetchDataFromPTM(hash) if !ok { //there is nothing to do here, the state wasn't shared with us log.Error("Extension: No state shared with us") return nil, nil, nil, false } var accounts map[string]extension.AccountWithMetadata if err := json.Unmarshal(stateData, &accounts); err != nil { log.Error("Extension: Could not unmarshal data") return nil, nil, nil, false } return managedParties, accounts, privacyMetaData, true } // Checks func (handler *ExtensionHandler) FetchDataFromPTM(hash string) ([]string, []byte, *state.PrivacyMetadata, bool) { ptmHash, _ := common.Base64ToEncryptedPayloadHash(hash) _, managedParties, stateData, extraMetaData, err := handler.ptm.Receive(ptmHash) if stateData == nil { log.Error("No state data found in PTM", "ptm hash", hash) return nil, nil, nil, false } if err != nil { log.Error("Error receiving state data from PTM", "ptm hash", hash, "err", err.Error()) return nil, nil, nil, false } privacyMetaData := state.NewStatePrivacyMetadata(ptmHash, extraMetaData.PrivacyFlag) return managedParties, stateData, privacyMetaData, true } func (handler *ExtensionHandler) UuidIsOwn(address common.Address, uuid string, psi types.PrivateStateIdentifier) bool { if uuid == "" { //we never called accept log.Warn("Extension: State shared by accept never called") return false } encryptedTxHash := common.BytesToEncryptedPayloadHash(common.FromHex(uuid)) isSender, err := handler.ptm.IsSender(encryptedTxHash) if err != nil { log.Debug("Extension: could not determine if we are sender", "err", err.Error()) return false } if !isSender { return false } senderPublicKey, _, encryptedPayload, _, err := handler.ptm.Receive(encryptedTxHash) if err != nil { log.Debug("Extension: payload not found", "err", err) return false } //check the given PSI is same as PSI of sender key senderPsm, err := handler.psmr.ResolveForManagedParty(senderPublicKey) if err != nil { log.Debug("Extension: unable to determine sender public key PSI", "err", err) return false } if senderPsm.ID != psi { // sender was another tenant on this node //not an error case, so no need to log an error return false } var payload common.DecryptRequest if err := json.Unmarshal(encryptedPayload, &payload); err != nil { log.Debug("Extension: payload unmarshal failed", "err", err) } contractDetails, _, err := handler.ptm.DecryptPayload(payload) if err != nil { log.Debug("Extension: payload decrypt failed", "err", err) } if !bytes.Equal(contractDetails, address.Bytes()) { log.Error("Extension: wrong address in retrieved UUID") return false } return true }