-
Notifications
You must be signed in to change notification settings - Fork 206
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit includes only all meaningful changes from the branch `ste…
…ve/add_limitations_to_validate_fn`, which at some point, that I cannot identify, introduced many unwanted old file changes.
- Loading branch information
Showing
7 changed files
with
242 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
215 changes: 215 additions & 0 deletions
215
...tarknet/modules/architecture_and_concepts/pages/Accounts/account_functions.adoc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
[id="account_interface_functions"] | ||
= Account interface function reference | ||
|
||
== Overview | ||
|
||
The functions in the table xref:#starknet_account_interface_functions[] are part of account contracts. Where required, you must include these functions within your contract. The logic of these functions can be mostly arbitrary, with a few limitations. For information on these limitations, see xref:#invalid_transactions[]. | ||
|
||
[#starknet_account_interface_functions] | ||
.Starknet account interface functions | ||
[cols="1,3"] | ||
|=== | ||
| Function name | When required | ||
|
||
| `+__validate__+` | Always required | ||
| `+__execute__+` | Always required | ||
| `+__validate_declare__+` | Required for a contract to be able to send a `DECLARE` transaction. | ||
| `+__validate_deploy__+` a| Required when deploying an instance of an account contract with a `DEPLOY_ACCOUNT` _transaction_. | ||
|
||
[NOTE] | ||
==== | ||
You can only use the `+__validate_deploy__+` function in an account contract to validate the `DEPLOY_ACCOUNT` transaction for that same contract. | ||
==== | ||
| `+__constructor__+` | If an account does not define a `+__constructor__+` function, the sequencer uses a default `+__constructor__+` function, which is empty. | ||
|=== | ||
|
||
When the sequencer receives a transaction request, it calls the corresponding validation function with the fields of the transaction request. | ||
|
||
For an `INVOKE` transaction, after successfully completing validation, the sequencer calls the `+__execute__+` function with the fields of the transaction request. | ||
|
||
For a `DEPLOY_ACCOUNT` transaction, the sequencer calls the `+__constructor__+` function with the fields of the transaction request. Then, after successfully completing validation, the deployment is finalized. | ||
|
||
|
||
* For more information on the available transaction types and their fields, see xref:architecture_and_concepts:Network_Architecture/transactions.adoc[Transaction types]. | ||
* For more information on the validation and execution stages, see xref:architecture_and_concepts:Network_Architecture/transaction-life-cycle.adoc[Transaction lifecycle]. | ||
|
||
Separating the validation and execution stages guarantees payment to sequencers for work completed and protects them from Denial of Service (DoS) attacks. | ||
|
||
[#attacks_that_validation_limitations_prevent] | ||
== Potential attacks | ||
|
||
The validation functions have limitations, described below, that are designed to prevent the following attacks: | ||
|
||
* Denial of Service (DoS) attacks. Without these limitations, an attack could cause the sequencer to perform a large amount of work before a transaction fails validation, such as by sending multiple `DEPLOY_ACCOUNT` transactions that are invalid as a result of the constructor or `+__validate_deploy__+` failing. This work would not be eligible for fee payment. | ||
* Even if the validation is simple, the following attack could still be possible: | ||
. An attacker fills the mempool with transactions that are valid at the time they are sent. | ||
. A sequencer starts executing them, thinking that by the time it produces a block, they will still be valid. | ||
. However, shortly after the transactions are sent, the attacker sends one transaction that somehow invalidates all the previous ones and makes sure it's included in the block, by offering higher fees for this one transaction, before the sequencer can publish the block. | ||
* Consider many validation functions checking that the value of a storage slot is `1`, and the attacker's transaction later sets it to `0`. Restricting validation functions from calling external contracts prevents this attack. | ||
|
||
[#limitations_of_validation] | ||
== Limitations on validation that prevent attacks | ||
|
||
The limitations listed here apply to the following validation functions: | ||
|
||
* `+__validate__+`, `+__validate_deploy__+`, and `+__validate_declare__+` | ||
* A constructor, when run in a `DEPLOY_ACCOUNT` transaction. That is, if an account is deployed from an existing class via the `deploy` syscall, these limitations do not apply. | ||
|
||
The validation functions have the following limitations: | ||
|
||
* You cannot call functions in external contracts, only in your account contract. | ||
+ | ||
[NOTE] | ||
==== | ||
This restriction enforces a single storage update being able to invalidate only transactions from a single account. However, be aware that an account can always invalidate its own past transactions by changing its keys. | ||
So the fees you need to pay to invalidate transactions in the mempool are directly proportional to the number of unique accounts. For example, if the fee you need to pay to invalidate a transaction from one account is stem:[$$x$$], then the price of invalidating ten transactions from ten different accounts is stem:[$$10x$$]. | ||
==== | ||
|
||
* The maximum number of computational steps, measured in Cairo steps, for a validation function is 1,000,000. | ||
* A builtin can be applied a limited number of times. For specific limits for each builtin, see xref:tools:limits_and_triggers.adoc[]. | ||
* Access is restricted to `sequencer_address` in the `get_execution_info` syscall. The syscall returns zero values for `sequencer_address`. | ||
* The values of `block_number` and `block_timestamp` in the `get_execution_info` syscall are modified as follows: | ||
** `block_timestamp` returns the hour, rounded down. | ||
** `block_number` returns the block number, rounded down to the nearest multiple of 100. | ||
* The following syscalls cannot be called: | ||
** `get_block_hash` | ||
** `get_sequencer_address` `get_sequencer_address` is only supported for Cairo 0 contracts. | ||
|
||
[id="invalid_transactions"] | ||
== Invalid transactions | ||
|
||
When the `+__validate__+`, `+__validate_deploy__+`, or `+__validate_declare__+`, function fails, the account in question does not pay any fee, and the transaction's status is `REJECTED`. | ||
|
||
[id="reverted_transactions"] | ||
== Reverted transactions | ||
|
||
A transaction has the status `REVERTED` when the `+__execute__+` function fails. A reverted transaction is included in a block, and the sequencer is eligible to charge a fee for the work done up to the point of failure, similar to Ethereum. | ||
|
||
== Function descriptions | ||
|
||
The functions in this section must be present in account contracts, as noted, with `+__execute__+` and `+__validate__+` required in all account contracts. However, you define the logic in the these functions as needed, unless noted otherwise, while adhering to the limitations specified in xref:#limitations_of_validation[]. As a result, the function descriptions below leave you room to define your own functionality. | ||
|
||
For examples of account contracts that implement these functions, see link:https://book.starknet.io/ch04-01-accounts.html[Account Contracts] in the Starknet Book. | ||
|
||
|
||
[id="__execute__"] | ||
=== `+__execute__+` | ||
|
||
.Description | ||
|
||
_Always required_ | ||
|
||
Initiates the execution stage in the sequencer. The sequencer calls this function upon receiving an `INVOKE` transaction, after the `+__validate__+` function successfully completes. | ||
|
||
In most implementations, `+__execute__+` initiates a sequence of calls from the account. | ||
|
||
The purpose of the `+__execute__+` function is to abstract away the remaining actions performed by a transaction. | ||
|
||
In Ethereum, a transaction is necessarily a call to a specific function in a smart contract. With the `+__execute__+` abstraction, the account designer controls the flow of the transaction. For example, you can natively support multicalls in your account, saving the need to send multiple transactions. In practice, however, #this# is even harder to manage without multicalls due to nonces. #What does _this_ refer to? Sending multiple transactions?# | ||
|
||
.Returns | ||
|
||
The list of each call's serialized return value. | ||
|
||
|
||
''' | ||
|
||
[id="__validate__"] | ||
=== `+__validate__+` | ||
|
||
.Description | ||
|
||
_Always required_ | ||
|
||
Initiates the validation stage in the sequencer. Validates the sender's address. The sequencer calls this function upon receiving an `INVOKE` transaction. | ||
|
||
In most implementations, `+__validate__+` ensures that only the account owner can initiate transactions. | ||
|
||
The `+__validate__+` function typically ensures that any transaction submitted was indeed initiated by the account owner and therefore does not take up unjustified resources during the execution process. | ||
|
||
|
||
Without this mechanism, a forged transaction could result in the sequencer stealing the user's funds. So the `+__validate__+` function ensures that the sequencer can only include transactions that were approved by the account owner. | ||
|
||
The arbitrary logic allowed in the `+__validate__+` function gives the account's designer the ability to determine what it means for a transaction to be valid, enabling different signature schemes and other xref:architecture_and_concepts:Accounts/introduction.adoc#examples[exotic accounts]. | ||
|
||
.Returns | ||
|
||
If the signature is verified, the function should return the string `VALID` as `felt252` value. If not, it should return any other value, such as `0`. | ||
|
||
|
||
''' | ||
|
||
[id="__validate_declare__"] | ||
=== `+__validate_declare__+` | ||
|
||
.Description | ||
|
||
_Required for a contract to be able to send a_ `DECLARE` _transaction._ | ||
|
||
The sequencer calls this function upon receiving a `DECLARE` transaction. | ||
|
||
If the contract declares other contracts and handles the corresponding gas fees, this function authenticates the contract declaration. | ||
|
||
.Parameters | ||
|
||
[horizontal,labelwidth="35",role="stripes-odd"] | ||
`class_hash: _felt_`:: The class hash. | ||
|
||
.Returns | ||
|
||
If the signature is verified, the function should return the string `VALID` as `felt252` value. If not, it should return any other value, such as `0`. | ||
|
||
|
||
|
||
''' | ||
|
||
[id="__validate_deploy__"] | ||
=== `+__validate_deploy__+` | ||
|
||
.Description | ||
|
||
_Required when deploying an account with a_ `DEPLOY_ACCOUNT` _transaction_. | ||
|
||
The sequencer calls this function upon receiving a `DEPLOY_ACCOUNT` transaction. Validates the deployment of the class referred to by the `class_hash` parameter in the transaction. | ||
|
||
You can use this function to set up an account contract without linking it to the address that deploys it or depending on another account contract for gas fees. When determining the contract's address, use the deployer address `0x0`. | ||
|
||
.Parameters | ||
|
||
[horizontal,labelwidth="35",role="stripes-odd"] | ||
`class_hash: _felt_`:: The class hash. | ||
`contract_address_salt: _felt_`:: The contract address salt. | ||
`<__constructor_arguments__>`:: The arguments expected by the contract’s constructor. The inputs to the constructor must be identical to the rest of the inputs for validate_deploy. The compiler enforces this requirement. | ||
|
||
[NOTE] | ||
==== | ||
In determining the contract address, the deployer address `0x0` is used. | ||
==== | ||
|
||
.Returns | ||
|
||
If the signature is verified, the function should return the string `VALID` as a `felt252` value. If not, it should return any other value, such as `0`. | ||
|
||
.Example | ||
|
||
Notice how the signature of `+__validate_deploy__+` is structured to consider the signature of the constructor: | ||
|
||
[#call_validate_deploy] | ||
[source,cairo,sub="quotes"] | ||
---- | ||
fn __validate_deploy__( | ||
self: @ComponentState<TContractState>, | ||
class_hash: felt252, | ||
contract_address_salt: felt252, | ||
public_key: felt252 | ||
) -> felt252 | ||
#[constructor] | ||
fn constructor(ref self: ContractState, public_key: felt252) | ||
---- | ||
|
||
[NOTE] | ||
==== | ||
You can access the transaction hash and value for `max_fee` by getting transaction information with the `get_execution_info` system call. | ||
==== |
29 changes: 12 additions & 17 deletions
29
components/Starknet/modules/architecture_and_concepts/pages/Accounts/approach.adoc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,32 @@ | ||
[id="starknet_account_structure"] | ||
= Starknet account interface | ||
= Starknet's account interface | ||
|
||
A Starknet account contract must include the following two functions: | ||
Starknet's account structure is inspired by Ethereum's EIP-4337, where instead of EOAs, you use smart contract accounts with arbitrary verification logic. | ||
|
||
* `+__validate__+` | ||
* `+__execute__+` | ||
While not mandatory at the protocol level, you can use a richer standard interface for accounts, defined in link:https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-6.md[Starknet Improvement Proposal #6 (SNIP-6)]. SNIP-6 was developed by community members at OpenZeppelin, in close collaboration with wallet teams and other Core Starknet developers. | ||
|
||
These functions serve distinct purposes to ensure that only the account owner can initiate transactions and that fees can be charged for the resources they use. | ||
[#account_functions] | ||
== Account functions | ||
|
||
Starknet's account type is inspired by Ethereum's EIP-4337, where instead of an account being an EOA, it is now a smart contract account with arbitrary verification logic. | ||
A valid account contract includes specific functions, depending on the type of the contract. For more information, see xref:architecture_and_concepts:Accounts/account_functions.adoc[]. | ||
|
||
Through the use of smart contracts, you are provided with complete flexibility within your account implementation. | ||
|
||
While not mandatory at the protocol level, a richer standard interface for accounts was developed by the community. This standard was developed by OpenZeppelin, in a close collaboration with wallet teams and other Core Starknet developers. You can see the traits as defined in https://github.com/ericnordelo/SNIPs/blob/feat/standard-account/SNIPS/snip-6.md[Starknet Improvement Proposal #6 (SNIP-6)]. | ||
|
||
[id="replay_protection"] | ||
[#replay_protection] | ||
== Replay protection | ||
|
||
In Starknet, similar to Ethereum, every contract has a nonce, which is sequential. When a transaction is sent from an account, the transaction's nonce must match the account's nonce. The account's nonce is incremented after the transaction is executed, whether or not the transaction is reverted. | ||
In Starknet, similar to Ethereum, every contract has a nonce, including an account contract. This nonce is sequential. The nonce of a transaction sent from an account must match the nonce of that account. After the transaction is executed, whether or not it is reverted, the nonce is incremented by one. | ||
|
||
[NOTE] | ||
==== | ||
In Starknet, only the nonce of account contracts, that is, those adhering to the above structure, can be non-zero. | ||
In Starknet, only the nonce of account contracts, that is, those adhering to the above structure, can be non-zero. | ||
In contrast, in Ethereum, regular smart contracts, known as _Contract Accounts_, as opposed to _Externally Owned Accounts_ can increment their nonce by deploying smart contracts, that is, executing the `CREATE` and `CREATE2` opcodes. | ||
In contrast, in Ethereum, regular smart contracts, known as _Contract Accounts_, as opposed to _Externally Owned Accounts_ can increment their nonce by deploying smart contracts, that is, executing the `CREATE` and `CREATE2` opcodes. | ||
For more information on accounts in Ethereum, see link:https://ethereum.org/en/developers/docs/accounts/[Ethereum Accounts] in the Ethereum documentation. | ||
==== | ||
|
||
A nonce serves two important roles: | ||
|
||
* It guarantees transaction hash uniqueness, which is important for a good user experience. | ||
* It provides replay protection to the account. Because the signature refers to a particular nonce, a malicious party cannot replay the transaction. | ||
|
||
While Starknet currently determines the sequential nonce structure at the protocol level, in the future, Starknet will consider a more flexible design, extending account abstraction to nonce management, also referred to as _nonce abstraction_. | ||
* It provides replay protection to the account: Because the signature is bound to a particular nonce, a malicious party cannot replay the transaction. | ||
|
||
Starknet currently determines the nonce structure at the protocol level to be sequential. In the future, Starknet will consider a more flexible design, extending account abstraction to nonce management, previously referred to as _nonce abstraction_. |
Oops, something went wrong.