Skip to content

Commit

Permalink
[aptos-framework] permissioned_delegation with rate limiter (#15114)
Browse files Browse the repository at this point in the history
token bucket for rate limiting.
  • Loading branch information
lightmark authored Jan 17, 2025
1 parent 8c11da3 commit 17540fa
Show file tree
Hide file tree
Showing 7 changed files with 965 additions and 100 deletions.
2 changes: 2 additions & 0 deletions aptos-move/framework/aptos-framework/doc/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ This is the reference documentation of the Aptos framework.
- [`0x1::object_code_deployment`](object_code_deployment.md#0x1_object_code_deployment)
- [`0x1::optional_aggregator`](optional_aggregator.md#0x1_optional_aggregator)
- [`0x1::ordered_map`](ordered_map.md#0x1_ordered_map)
- [`0x1::permissioned_delegation`](permissioned_delegation.md#0x1_permissioned_delegation)
- [`0x1::permissioned_signer`](permissioned_signer.md#0x1_permissioned_signer)
- [`0x1::primary_fungible_store`](primary_fungible_store.md#0x1_primary_fungible_store)
- [`0x1::randomness`](randomness.md#0x1_randomness)
- [`0x1::randomness_api_v0_config`](randomness_api_v0_config.md#0x1_randomness_api_v0_config)
- [`0x1::randomness_config`](randomness_config.md#0x1_randomness_config)
- [`0x1::randomness_config_seqnum`](randomness_config_seqnum.md#0x1_randomness_config_seqnum)
- [`0x1::rate_limiter`](rate_limiter.md#0x1_rate_limiter)
- [`0x1::reconfiguration`](reconfiguration.md#0x1_reconfiguration)
- [`0x1::reconfiguration_state`](reconfiguration_state.md#0x1_reconfiguration_state)
- [`0x1::reconfiguration_with_dkg`](reconfiguration_with_dkg.md#0x1_reconfiguration_with_dkg)
Expand Down
323 changes: 223 additions & 100 deletions aptos-move/framework/aptos-framework/doc/permissioned_delegation.md

Large diffs are not rendered by default.

180 changes: 180 additions & 0 deletions aptos-move/framework/aptos-framework/doc/rate_limiter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@

<a id="0x1_rate_limiter"></a>

# Module `0x1::rate_limiter`



- [Enum Resource `RateLimiter`](#0x1_rate_limiter_RateLimiter)
- [Function `initialize`](#0x1_rate_limiter_initialize)
- [Function `request`](#0x1_rate_limiter_request)
- [Function `refill`](#0x1_rate_limiter_refill)


<pre><code><b>use</b> <a href="timestamp.md#0x1_timestamp">0x1::timestamp</a>;
</code></pre>



<a id="0x1_rate_limiter_RateLimiter"></a>

## Enum Resource `RateLimiter`



<pre><code>enum <a href="rate_limiter.md#0x1_rate_limiter_RateLimiter">RateLimiter</a> <b>has</b> <b>copy</b>, drop, store, key
</code></pre>



<details>
<summary>Variants</summary>


<details>
<summary>TokenBucket</summary>


<details>
<summary>Fields</summary>


<dl>
<dt>
<code>capacity: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>current_amount: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>refill_interval: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>last_refill_timestamp: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>fractional_accumulated: u64</code>
</dt>
<dd>

</dd>
</dl>


</details>

</details>

</details>

<a id="0x1_rate_limiter_initialize"></a>

## Function `initialize`



<pre><code><b>public</b> <b>fun</b> <a href="rate_limiter.md#0x1_rate_limiter_initialize">initialize</a>(capacity: u64, refill_interval: u64): <a href="rate_limiter.md#0x1_rate_limiter_RateLimiter">rate_limiter::RateLimiter</a>
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="rate_limiter.md#0x1_rate_limiter_initialize">initialize</a>(capacity: u64, refill_interval: u64): <a href="rate_limiter.md#0x1_rate_limiter_RateLimiter">RateLimiter</a> {
RateLimiter::TokenBucket {
capacity,
current_amount: capacity, // Start <b>with</b> a full bucket (full capacity of transactions allowed)
refill_interval,
last_refill_timestamp: <a href="timestamp.md#0x1_timestamp_now_seconds">timestamp::now_seconds</a>(),
fractional_accumulated: 0, // Start <b>with</b> no fractional accumulated
}
}
</code></pre>



</details>

<a id="0x1_rate_limiter_request"></a>

## Function `request`



<pre><code><b>public</b> <b>fun</b> <a href="rate_limiter.md#0x1_rate_limiter_request">request</a>(limiter: &<b>mut</b> <a href="rate_limiter.md#0x1_rate_limiter_RateLimiter">rate_limiter::RateLimiter</a>, num_token_requested: u64): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="rate_limiter.md#0x1_rate_limiter_request">request</a>(limiter: &<b>mut</b> <a href="rate_limiter.md#0x1_rate_limiter_RateLimiter">RateLimiter</a>, num_token_requested: u64): bool {
<a href="rate_limiter.md#0x1_rate_limiter_refill">refill</a>(limiter);
<b>if</b> (limiter.current_amount &gt;= num_token_requested) {
limiter.current_amount = limiter.current_amount - num_token_requested;
<b>true</b>
} <b>else</b> {
<b>false</b>
}
}
</code></pre>



</details>

<a id="0x1_rate_limiter_refill"></a>

## Function `refill`



<pre><code><b>fun</b> <a href="rate_limiter.md#0x1_rate_limiter_refill">refill</a>(limiter: &<b>mut</b> <a href="rate_limiter.md#0x1_rate_limiter_RateLimiter">rate_limiter::RateLimiter</a>)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>fun</b> <a href="rate_limiter.md#0x1_rate_limiter_refill">refill</a>(limiter: &<b>mut</b> <a href="rate_limiter.md#0x1_rate_limiter_RateLimiter">RateLimiter</a>) {
<b>let</b> current_time = <a href="timestamp.md#0x1_timestamp_now_seconds">timestamp::now_seconds</a>();
<b>let</b> time_passed = current_time - limiter.last_refill_timestamp;
// Calculate the full tokens that can be added
<b>let</b> accumulated_amount = time_passed * limiter.capacity + limiter.fractional_accumulated;
<b>let</b> new_tokens = accumulated_amount / limiter.refill_interval;
<b>if</b> (limiter.current_amount + new_tokens &gt;= limiter.capacity) {
limiter.current_amount = limiter.capacity;
limiter.fractional_accumulated = 0;
} <b>else</b> {
limiter.current_amount = limiter.current_amount + new_tokens;
// Update the fractional amount accumulated for the next refill cycle
limiter.fractional_accumulated = accumulated_amount % limiter.refill_interval;
};
limiter.last_refill_timestamp = current_time;
}
</code></pre>



</details>


[move-book]: https://aptos.dev/move/book/SUMMARY
176 changes: 176 additions & 0 deletions aptos-move/framework/aptos-framework/doc/token_bucket.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@

<a id="0x1_token_bucket"></a>

# Module `0x1::token_bucket`



- [Resource `Bucket`](#0x1_token_bucket_Bucket)
- [Function `initialize_bucket`](#0x1_token_bucket_initialize_bucket)
- [Function `request`](#0x1_token_bucket_request)
- [Function `refill`](#0x1_token_bucket_refill)


<pre><code><b>use</b> <a href="../../aptos-stdlib/doc/math64.md#0x1_math64">0x1::math64</a>;
<b>use</b> <a href="timestamp.md#0x1_timestamp">0x1::timestamp</a>;
</code></pre>



<a id="0x1_token_bucket_Bucket"></a>

## Resource `Bucket`



<pre><code><b>struct</b> <a href="token_bucket.md#0x1_token_bucket_Bucket">Bucket</a> <b>has</b> <b>copy</b>, drop, store, key
</code></pre>



<details>
<summary>Fields</summary>


<dl>
<dt>
<code>capacity: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>tokens: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>refill_rate_per_minute: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>last_refill_timestamp: u64</code>
</dt>
<dd>

</dd>
<dt>
<code>fractional_time_accumulated: u64</code>
</dt>
<dd>

</dd>
</dl>


</details>

<a id="0x1_token_bucket_initialize_bucket"></a>

## Function `initialize_bucket`



<pre><code><b>public</b> <b>fun</b> <a href="token_bucket.md#0x1_token_bucket_initialize_bucket">initialize_bucket</a>(capacity: u64): <a href="token_bucket.md#0x1_token_bucket_Bucket">token_bucket::Bucket</a>
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="token_bucket.md#0x1_token_bucket_initialize_bucket">initialize_bucket</a>(capacity: u64): <a href="token_bucket.md#0x1_token_bucket_Bucket">Bucket</a> {
<b>let</b> bucket = <a href="token_bucket.md#0x1_token_bucket_Bucket">Bucket</a> {
capacity,
tokens: capacity, // Start <b>with</b> a full bucket (full capacity of transactions allowed)
refill_rate_per_minute: capacity,
last_refill_timestamp: <a href="timestamp.md#0x1_timestamp_now_seconds">timestamp::now_seconds</a>(),
fractional_time_accumulated: 0, // Start <b>with</b> no fractional time accumulated
};
bucket
}
</code></pre>



</details>

<a id="0x1_token_bucket_request"></a>

## Function `request`



<pre><code><b>public</b> <b>fun</b> <a href="token_bucket.md#0x1_token_bucket_request">request</a>(bucket: &<b>mut</b> <a href="token_bucket.md#0x1_token_bucket_Bucket">token_bucket::Bucket</a>, num_token_requested: u64): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="token_bucket.md#0x1_token_bucket_request">request</a>(bucket: &<b>mut</b> <a href="token_bucket.md#0x1_token_bucket_Bucket">Bucket</a>, num_token_requested: u64): bool {
<a href="token_bucket.md#0x1_token_bucket_refill">refill</a>(bucket);
<b>if</b> (bucket.tokens &gt;= num_token_requested) {
bucket.tokens = bucket.tokens - num_token_requested;
<b>true</b>
} <b>else</b> {
<b>false</b>
}
}
</code></pre>



</details>

<a id="0x1_token_bucket_refill"></a>

## Function `refill`



<pre><code><b>fun</b> <a href="token_bucket.md#0x1_token_bucket_refill">refill</a>(bucket: &<b>mut</b> <a href="token_bucket.md#0x1_token_bucket_Bucket">token_bucket::Bucket</a>)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>fun</b> <a href="token_bucket.md#0x1_token_bucket_refill">refill</a>(bucket: &<b>mut</b> <a href="token_bucket.md#0x1_token_bucket_Bucket">Bucket</a>) {
<b>let</b> current_time = <a href="timestamp.md#0x1_timestamp_now_seconds">timestamp::now_seconds</a>();
<b>let</b> time_passed = current_time - bucket.last_refill_timestamp;

// Total time passed including fractional accumulated time
<b>let</b> total_time = time_passed + bucket.fractional_time_accumulated;

// Calculate the full tokens that can be added
<b>let</b> new_tokens = total_time * bucket.refill_rate_per_minute / 60;

// Calculate the remaining fractional time
<b>let</b> remaining_fractional_time = total_time % 60;

// Refill the bucket <b>with</b> the full tokens
<b>if</b> (new_tokens &gt; 0) {
bucket.tokens = <a href="../../aptos-stdlib/doc/math64.md#0x1_math64_min">math64::min</a>(bucket.tokens + new_tokens, bucket.capacity);
bucket.last_refill_timestamp = current_time;
};

// Update the fractional time accumulated for the next refill cycle
bucket.fractional_time_accumulated = remaining_fractional_time;
}
</code></pre>



</details>


[move-book]: https://aptos.dev/move/book/SUMMARY
Loading

0 comments on commit 17540fa

Please sign in to comment.