diff --git a/HIP/hip-792.md b/HIP/hip-792.md new file mode 100644 index 000000000..01971ef40 --- /dev/null +++ b/HIP/hip-792.md @@ -0,0 +1,291 @@ +--- +hip: 792 +title: Extend isAuthorized to process current transaction in HAS System Contract +author: Brendan Graetz <@bguiz> +working-group: Nana Essilfie-Conduah <@nana-ec>, Luke Lee <@lukelee-sl> +type: Standards Track +category: Service +needs-council-approval: Yes +status: Draft +last-call-date-time: 2023-10-22T16:00:00Z +created: 2023-08-21 +discussions-to: https://github.com/hashgraph/hedera-improvement-proposal/discussions/793 +updated: 2023-08-23 +requires: 632 +--- + +## Abstract + + + +HIP-632 adds a new system contract, `hederaAccountService` that exposes a method `isAuthorized(address, messageHash, signatureBlob)`. This HIP proposes a similar version of that function, which implements the same functionality, but restricted for use *only* on the current (in flight) transaction. This exposes a new method `isAuthorizedCurrentTransaction()`. + +## Motivation + + + +`hederaAccountService.isAuthorized(address, messageHash, signatureBlob)` does work for the following scenarios: + +- When an account's admin key is "simple", and is comprised of either a single EdDSA key, or a single ECDSA key +- When an account's admin key is "complex", and is comprised of multiple EdDSA keys and/or ECDSA keys, combined using one or more `KeyList`s or `ThresholdKey`s. + +`hederaAccountService.isAuthorized(address, messageHash, signatureBlob)` does **not** work for the following scenarios: + +- When an account's admin key is "complex", and is comprised of multiple EdDSA keys and/or ECDSA keys and/or **smart contract IDs**, combined using one or more `KeyList`s or `ThresholdKey`s. + +The proposed `hederaAccountService.isAuthorizedCurrentTransaction()` method aims to fulfil the above scenario, and specific use cases pertaining to this scenario will be elaborated upon in the [use cases section](#use-cases) below. + +Furthermore, Hedera Token Service exposes an authorization mechanism already, +which is capable of handling this scenario that is presently unfulfilled by Hedera Account Service as described in HIP-632. + + +> NOTE: +> +> - "EdDSA" refers to **EdDSA ED25519**, and +> - "ECDSA" refers to **ECDSA secp256k1** throughout this HIP, unless otherwise stated. +> +> These are the only types of cryptographic keys currently supported by Hedera's account system. + +## Rationale + + + +In existing code examples where `ecrecover` is used, +a smart contract function is passed in the transaction data in its parameters. +The design of both `hederaAcountService.isAuthorized(address, messageHash, signatureBlob)` +and `hederaAcountService.isAuthorizedRaw(address, messageHash, signatureBlob)` +in HIP-632 mimics this approach. + +This approach is adequate in situations where we assume that: + +(1) All authorization is performed using cryptographic signatures (EdDSA and/or ECDSA in the case of Hedera). + +(2) All authorization is performed "off-chain", that is among clients, and not within (or by) smart contracts. + +On Ethereum and other EVM-compatible networks, +this approach is sufficient because Externally Owned Acounts (EOAs) +are the only type of account that exists on, +and is supported by the network. + +However, this is **not** the case for Hedera. +While EVM-compatible, +Hedera has an account system that supports "simple" keys on acounts +(which are approximately analogous to EOAs). +Hedera simultaneously supports "complex" keys on accounts +(which have no analogue on EVM-compatible networks). +These complex accounts require special consideration as they support +`KeyList`s and `ThresholdKey`s (which may be recursively nested), +and whose "leaf nodes" may be comprised of any of: +EdDSA keys, ECDSA keys, and even **smart contract IDs**. + +The authorization methods described in HIP-632 are sufficient to support +the "complex" keys on accounts, as described above, with one exception: +When the "leaf nodes" of a "complex" key include one or more **smart contract IDs**. +In this situation, both assumptions (1) and (2) listed above can no longer be held true: + +(1) Smart contracts do not have cryptographic keys, +and therefore cannot sign a transaction in order to authorize it. + +(2) Smart contract execution occurs exclusively "on-chain", +and therefore a smart contract may not provide its authorization of a transaction +by any means other than its own execution when invoked within a transaction. +In other words smart contract authorization must necessarily occur while a transaction is "in flight", +and therefore cannot occur client-side before being submitted to the network. + +However the latter scenario with smart contract IDs +within "complex" keys **should** be supported, as noted in +[Hedera's documentation on Keys](https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/basic-types/key): + +> Note that when a Key is a smart contract ID, +> it doesn't mean the contract with that ID will actually create a cryptographic signature. +> It only means that when the contract calls a system contract function, +> the resulting "child transaction" will be authorized to perform any action controlled by the Key. + +Therefore this HIP proposes a means, via the `hederaAccountSystem` system contract, +to verify authorization of a transaction that will work in the above scenarios. + +> NOTE: +> +> Hedera Token Service already exposes a system contract `hederaTokenService`, +> and its function already performs the same authorization as proposed +> for `hederaAccountService.isAuthorizedCurrentTransaction()` +> +> This works as system contracts, including `hederaTokenService`, +> are passed in a [`TxnAwareEvmSigsVerifier`](https://github.com/hashgraph/hedera-services/blob/810971de2b/hedera-node/hedera-mono-service/src/main/java/com/hedera/node/app/service/mono/contracts/sources/TxnAwareEvmSigsVerifier.java#L60), +> which has a [`TransactionContext`](https://github.com/hashgraph/hedera-services/blob/810971de2b/hedera-node/hedera-mono-service/src/main/java/com/hedera/node/app/service/mono/contracts/sources/TxnAwareEvmSigsVerifier.java#L70) +> that contains the necessary information in [`JKey`](https://github.com/hashgraph/hedera-services/blob/810971de2b/hedera-node/hedera-mono-service/src/main/java/com/hedera/node/app/service/mono/legacy/core/jproto/JKey.java#L37). +> + +## User stories + + + +(1) +As a smart contract developer, +I want to code a smart contract in solidity which is able to identify whether a transaction is authorized when sent from an account with a complex key which contains a smart contract ID, +so that I can implement advanced use cases including: + +- implement flexible and customisable authorisation rules +- implement advanced multisig use cases without the need to split across multiple transactions +- implement atomic multisig use cases +- implement batch processing of multiple transactions + +(2) +As a user of Hedera networks, +I want to create an 1-of-2 threshold key on my Hedera account where 1 component of my complex key is either an EdDSA key or an ECDSA key and the other component is a specified smart contract ID, +so that the particular smart contract specified in my threshold key can perform actions on behalf of my account. + +## Specification + + + +An augmentation of the existing system contract specified in HIP-632, `hederaAccountService`, with 1 new function to expand authorization checks is proposed. + +This will aid developers who were limited to `ECRECOVER` authorization flows, and `hederaAccountService.isAuthorized(address, messageHash, signatureBlob)` flows, who will now be able to expand authorization checks to include smart contract ID based authorization. + +| hash | signature | return | description | +| --- | --- | --- | --- | +| | isAuthorizedCurrentTransaction() | bool | `true` if account is authorized to carry out transaction execution on account. Accepts protobuf key signature blobs. May be used for ECDSA, EdDSA simple key flows, and complex key flows which include any of ECDSA keys, EdDSA keys, and smart contract IDs. | + +### `isAuthorizedCurrentTransaction()` Function Usage + +This function behaves identically to `isAuthorized(address, messageHash, signatureBlob)` as defined in HIP-632, with the following key differences: + +- It is called without specifying any parameters +- This function extracts the values that it needs in order to validate if a transaction is authorized from the current transaction +- Therefore it designed to be used exclusively on the current transaction, which is still in-flight + - This is clearly communicated by the `CurrentTransaction` suffix in the function name + +No new protocol buffer schema definitions are needed as there are no parameters for this function. +Internal protocol buffer schema definitions that need to be used to process this function +would be the existing ones already present in Hedera's base account system, +such as `Key`, `ContractID`, `KeyList` and `ThresholdKey`. Potentially, this function may also use `SignatureMap` and `SignaturePair`, +as defined in HIP-632, if deemed necessary during implementation. + +### Example usage flows + +Happy path example: + +- Account `0.0.12345` has a `ThresholdKey` of ([`customSc`, `edDsaKey`, `ecDsaKey`], 3) --> transactions need to be authorised by all 3. +- `customSc` is a smart contract that has been deployed to HSCS +- `customSc` contains a function `foo` which invokes `hederaAcountService.isAuthorizedCurrentTransaction()` +- Transaction `tx` with `customSc.foo` invocation is instantiated, client-side +- `tx` is signed by `edDsaKey`, client-side +- `tx` is also subsequently signed by `ecDsaKey`, client-side +- `tx` is executed by submitting it to the network +- HSCS' EVM parses `tx` and invokes the function `customSc.foo` +- This in turn invokes the system contract function + `hederaAcountService.isAuthorizedCurrentTransaction()` +- `hederaAcountService` invokes the system contract implementation, + which uses `TxnAwareEvmSigsVerifier` to determine that `tx` is authorised, because: + - `tx` has been signed by `edDsaKey`, which is a member of account `0.0.12345`'s `ThresholdKey` + - `tx` has also been signed by `ecDsaKey`, which is a member of account `0.0.12345`'s `ThresholdKey` + - `tx` invokes `customSc`, which is a member of account `0.0.12345`'s `ThresholdKey` + - Put together, all 3 out of the required threshold of 3 have been met +- A `true` return value from `hederaAcountService.isAuthorizedCurrentTransaction()` is obtained within `customSc.foo` +- `customSc.foo` uses this return value to determine that the transaction is indeed **authorized**, and therefore should execute the **happy path** for the remainder of its function + +Error path example: + +- Account `0.0.12345` has a `ThresholdKey` of ([`customSc`, `edDsaKey`, `ecDsaKey`], 3) --> transactions need to be authorised by all 3. +- `customScOther` is a smart contract that has been deployed to HSCS +- `customScOther` contains a function `foo` which invokes `hederaAcountService.isAuthorizedCurrentTransaction()` +- Transaction `tx` with `customScOther.foo` invocation is instantiated, client-side +- `tx` is signed by `edDsaKey`, client-side +- `tx` is also subsequently signed by `ecDsaKey`, client-side +- `tx` is executed by submitting it to the network +- HSCS' EVM parses `tx` and invokes the function `customScOther.foo` +- This in turn invokes the system contract function + `hederaAcountService.isAuthorizedCurrentTransaction()` +- `hederaAcountService` invokes the system contract implementation, + which uses `TxnAwareEvmSigsVerifier` to determine that `tx` is **not** authorised, because: + - `tx` has been signed by `edDsaKey`, which is a member of account `0.0.12345`'s `ThresholdKey` + - `tx` has also been signed by `ecDsaKey`, which is a member of account `0.0.12345`'s `ThresholdKey` + - `tx` invokes `customScOther`, which is **not** a member of account `0.0.12345`'s `ThresholdKey` + - Put together, only 2 out of the required threshold of 3 have been met +- A `false` return value from `hederaAcountService.isAuthorizedCurrentTransaction()` is obtained within `customScOther.foo` +- `customScOther.foo` uses this return value to determine that the transaction is indeed **unauthorized**, and therefore should execute the **error path** for the remainder of its function. + +## Backwards compatibility + + + +This functionality is newly proposed and thus does not overwrite or alter existing functionality. + +Notably, this HIP proposes changes to +neither `isAuthorized(address, messageHash, signatureBlob)` +nor `isAuthorizedRaw(address, messageHash, signatureBlob)` +from HIP-632. + +## Security implications + + + +It vital that this proposal considers +the [new model (v2) boundaries](https://docs.hedera.com/hedera/core-concepts/smart-contracts/security#new-model-v2-boundaries) +and does not break its stipulations. + +Specifically: + +- Consider that top-level signatures are not supported +- Consider that `delegatecall` on the system contract is not supported + +Consider that smart contract developers may do the following: + +- Multiple smart contracts utilize the `isAuthorizedCurrentTransaction` call to do multiple things +- Authorize all potential uses of a user's signature in the parent transaction + +These could imply the user has given their authorization for all such combinations. Therefore sufficient warnings should be embedded in any [educational materials](#how-to-teach-this) related to this. + +## How to teach this + + + +Provide a [short, self contained, correct code example](http://sscce.org/) +which demonstrates this HIP, with both happy path and error path examples. +This will be in the style of existing work: + +- [Multisig Account](https://github.com/hedera-dev/hedera-code-snippets/tree/main/multisig-account) +- [Multisig Smart Contract Account](https://github.com/hedera-dev/hedera-code-snippets/tree/main/multisig-sc-account) + +Provide sufficient warnings about improper use of `isAuthorizedCurrentTransaction` in a tutorial, +at minimum including a list of "Do's and Don'ts". + +## Reference Implementations + + + +Nil + + + +## Rejected Ideas + + + +- Allow `delegatecall` on the `hederaAccountService` system contract + - Rejected because: Contradiction of v2 smart contract security model + - If there is indeed a community request that asks from specific exemption, we can ask them to submit a HIP that would specifically whitelist those specific flows, and then consider those. + - This path has already been trodden with HTS - "System smart contracts may not be delegate called, except from the Token proxy/facade flow, e.g., HIP 719. In such cases, HTS tokens are represented as smart contracts (see HIP 218) for common ERC methods." + +## Open Issues + + + +Nil + +## References + + + +- [HIP-632 - Hedera Account Service (HAS) System Contract](../hip-632) +- [Hedera - Basic Types - Key](https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/basic-types/key) +- [Hedera - Smart Contract Security - Security Model - New model (v2) boundaries](https://docs.hedera.com/hedera/core-concepts/smart-contracts/security#new-model-v2-boundaries) +- [Github - hedera-services `TxnAwareEvmSigsVerifier`](https://github.com/hashgraph/hedera-services/blob/810971de2b/hedera-node/hedera-mono-service/src/main/java/com/hedera/node/app/service/mono/contracts/sources/TxnAwareEvmSigsVerifier.java#L60) +- [Github - hedera-services `TransactionContext`](https://github.com/hashgraph/hedera-services/blob/810971de2b/hedera-node/hedera-mono-service/src/main/java/com/hedera/node/app/service/mono/contracts/sources/TxnAwareEvmSigsVerifier.java#L70) +- [Github - hedera-services `TransactionContext`](https://github.com/hashgraph/hedera-services/blob/810971de2b/hedera-node/hedera-mono-service/src/main/java/com/hedera/node/app/service/mono/legacy/core/jproto/JKey.java#L37) +- [Ethereum - `ecrecover` Precompiled Contract](https://ethereum.github.io/execution-specs/autoapi/ethereum/frontier/vm/precompiled_contracts/ecrecover/index.html) + +## Copyright/license + +This document is licensed under the Apache License, Version 2.0 -- see [LICENSE](../LICENSE) or [`https://www.apache.org/licenses/LICENSE-2.0`](https://www.apache.org/licenses/LICENSE-2.0)