Skip to content

Commit

Permalink
[sui-framework] Reserve addresses for the deny list
Browse files Browse the repository at this point in the history
  • Loading branch information
tnowacki committed May 8, 2024
1 parent 12c01b2 commit a5d9b06
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 14 deletions.
31 changes: 30 additions & 1 deletion crates/sui-framework/docs/sui-framework/deny_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ list.
- [Function `per_type_list`](#0x2_deny_list_per_type_list)


<pre><code><b>use</b> <a href="../sui-framework/bag.md#0x2_bag">0x2::bag</a>;
<pre><code><b>use</b> <a href="../move-stdlib/vector.md#0x1_vector">0x1::vector</a>;
<b>use</b> <a href="../sui-framework/bag.md#0x2_bag">0x2::bag</a>;
<b>use</b> <a href="../sui-framework/object.md#0x2_object">0x2::object</a>;
<b>use</b> <a href="../sui-framework/table.md#0x2_table">0x2::table</a>;
<b>use</b> <a href="../sui-framework/transfer.md#0x2_transfer">0x2::transfer</a>;
Expand Down Expand Up @@ -132,6 +133,16 @@ The index into the deny list vector for the <code>sui::coin::Coin</code> type.



<a name="0x2_deny_list_EInvalidAddress"></a>

The specified address is cannot be added to the deny list.


<pre><code><b>const</b> <a href="../sui-framework/deny_list.md#0x2_deny_list_EInvalidAddress">EInvalidAddress</a>: u64 = 1;
</code></pre>



<a name="0x2_deny_list_ENotDenied"></a>

The specified address to be removed is not already in the deny list.
Expand All @@ -142,6 +153,18 @@ The specified address to be removed is not already in the deny list.



<a name="0x2_deny_list_RESERVED"></a>

These addresses are reserved and cannot be added to the deny list.
The addresses listed are well known package and object addresses. So it would be
meaningless to add them to the deny list. As such, they are reserved for internal use.


<pre><code><b>const</b> <a href="../sui-framework/deny_list.md#0x2_deny_list_RESERVED">RESERVED</a>: <a href="../move-stdlib/vector.md#0x1_vector">vector</a>&lt;<b>address</b>&gt; = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1027, 57065];
</code></pre>



<a name="0x2_deny_list_add"></a>

## Function `add`
Expand All @@ -167,6 +190,8 @@ the type specified is the type of the coin, not the coin type itself. For exampl
`type`: <a href="../move-stdlib/vector.md#0x1_vector">vector</a>&lt;u8&gt;,
addr: <b>address</b>,
) {
<b>let</b> reserved = <a href="../sui-framework/deny_list.md#0x2_deny_list_RESERVED">RESERVED</a>;
<b>assert</b>!(!reserved.<a href="../sui-framework/deny_list.md#0x2_deny_list_contains">contains</a>(&addr), <a href="../sui-framework/deny_list.md#0x2_deny_list_EInvalidAddress">EInvalidAddress</a>);
<b>let</b> bag_entry: &<b>mut</b> <a href="../sui-framework/deny_list.md#0x2_deny_list_PerTypeList">PerTypeList</a> = &<b>mut</b> <a href="../sui-framework/deny_list.md#0x2_deny_list">deny_list</a>.lists[per_type_index];
bag_entry.<a href="../sui-framework/deny_list.md#0x2_deny_list_per_type_list_add">per_type_list_add</a>(`type`, addr)
}
Expand Down Expand Up @@ -239,6 +264,8 @@ Aborts with <code><a href="../sui-framework/deny_list.md#0x2_deny_list_ENotDenie
`type`: <a href="../move-stdlib/vector.md#0x1_vector">vector</a>&lt;u8&gt;,
addr: <b>address</b>,
) {
<b>let</b> reserved = <a href="../sui-framework/deny_list.md#0x2_deny_list_RESERVED">RESERVED</a>;
<b>assert</b>!(!reserved.<a href="../sui-framework/deny_list.md#0x2_deny_list_contains">contains</a>(&addr), <a href="../sui-framework/deny_list.md#0x2_deny_list_EInvalidAddress">EInvalidAddress</a>);
<a href="../sui-framework/deny_list.md#0x2_deny_list_per_type_list_remove">per_type_list_remove</a>(&<b>mut</b> <a href="../sui-framework/deny_list.md#0x2_deny_list">deny_list</a>.lists[per_type_index], `type`, addr)
}
</code></pre>
Expand Down Expand Up @@ -304,6 +331,8 @@ Returns true iff the given address is denied for the given type.
`type`: <a href="../move-stdlib/vector.md#0x1_vector">vector</a>&lt;u8&gt;,
addr: <b>address</b>,
): bool {
<b>let</b> reserved = <a href="../sui-framework/deny_list.md#0x2_deny_list_RESERVED">RESERVED</a>;
<b>if</b> (reserved.<a href="../sui-framework/deny_list.md#0x2_deny_list_contains">contains</a>(&addr)) <b>return</b> <b>false</b>;
<a href="../sui-framework/deny_list.md#0x2_deny_list_per_type_list_contains">per_type_list_contains</a>(&<a href="../sui-framework/deny_list.md#0x2_deny_list">deny_list</a>.lists[per_type_index], `type`, addr)
}
</code></pre>
Expand Down
38 changes: 38 additions & 0 deletions crates/sui-framework/packages/sui-framework/sources/deny_list.move
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,37 @@ module sui::deny_list {
const ENotSystemAddress: u64 = 0;
/// The specified address to be removed is not already in the deny list.
const ENotDenied: u64 = 1;
/// The specified address is cannot be added to the deny list.
const EInvalidAddress: u64 = 1;

/// The index into the deny list vector for the `sui::coin::Coin` type.
const COIN_INDEX: u64 = 0;

/// These addresses are reserved and cannot be added to the deny list.
/// The addresses listed are well known package and object addresses. So it would be
/// meaningless to add them to the deny list. As such, they are reserved for internal use.
const RESERVED: vector<address> = vector[
@0x0,
@0x1,
@0x2,
@0x3,
@0x4,
@0x5,
@0x6,
@0x7,
@0x8,
@0x9,
@0xA,
@0xB,
@0xC,
@0xD,
@0xE,
@0xF,
@0x403,
@0xDEE9,
];


/// A shared object that stores the addresses that are blocked for a given core type.
public struct DenyList has key {
id: UID,
Expand Down Expand Up @@ -46,6 +73,8 @@ module sui::deny_list {
`type`: vector<u8>,
addr: address,
) {
let reserved = RESERVED;
assert!(!reserved.contains(&addr), EInvalidAddress);
let bag_entry: &mut PerTypeList = &mut deny_list.lists[per_type_index];
bag_entry.per_type_list_add(`type`, addr)
}
Expand Down Expand Up @@ -78,6 +107,8 @@ module sui::deny_list {
`type`: vector<u8>,
addr: address,
) {
let reserved = RESERVED;
assert!(!reserved.contains(&addr), EInvalidAddress);
per_type_list_remove(&mut deny_list.lists[per_type_index], `type`, addr)
}

Expand All @@ -103,6 +134,8 @@ module sui::deny_list {
`type`: vector<u8>,
addr: address,
): bool {
let reserved = RESERVED;
if (reserved.contains(&addr)) return false;
per_type_list_contains(&deny_list.lists[per_type_index], `type`, addr)
}

Expand Down Expand Up @@ -145,6 +178,11 @@ module sui::deny_list {
}
}

#[test_only]
public fun reserved_addresses(): vector<address> {
RESERVED
}

#[test_only]
public fun create_for_test(ctx: &mut TxContext) {
create(ctx);
Expand Down
54 changes: 41 additions & 13 deletions crates/sui-framework/packages/sui-framework/tests/coin_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -115,36 +115,64 @@ module sui::coin_tests {
// test freezing an address
scenario.next_tx(TEST_ADDR);
let mut deny_list: deny_list::DenyList = scenario.take_shared();
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @1), 0);
coin::deny_list_add(&mut deny_list, &mut deny_cap, @1, scenario.ctx());
assert!(coin::deny_list_contains<COIN_TESTS>(&deny_list, @1), 0);
coin::deny_list_remove(&mut deny_list, &mut deny_cap, @1, scenario.ctx());
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @1), 0);
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @100), 0);
coin::deny_list_add(&mut deny_list, &mut deny_cap, @100, scenario.ctx());
assert!(coin::deny_list_contains<COIN_TESTS>(&deny_list, @100), 0);
coin::deny_list_remove(&mut deny_list, &mut deny_cap, @100, scenario.ctx());
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @100), 0);
test_scenario::return_shared(deny_list);
};
{
// test freezing an address over multiple "transactions"
scenario.next_tx(TEST_ADDR);
let mut deny_list: deny_list::DenyList = scenario.take_shared();
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @1), 0);
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @2), 0);
coin::deny_list_add(&mut deny_list, &mut deny_cap, @2, scenario.ctx());
assert!(coin::deny_list_contains<COIN_TESTS>(&deny_list, @2), 0);
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @100), 0);
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @200), 0);
coin::deny_list_add(&mut deny_list, &mut deny_cap, @200, scenario.ctx());
assert!(coin::deny_list_contains<COIN_TESTS>(&deny_list, @200), 0);
test_scenario::return_shared(deny_list);

scenario.next_tx(TEST_ADDR);
let mut deny_list: deny_list::DenyList = scenario.take_shared();
assert!(coin::deny_list_contains<COIN_TESTS>(&deny_list, @2), 0);
coin::deny_list_remove(&mut deny_list, &mut deny_cap, @2, scenario.ctx());
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @2), 0);
assert!(coin::deny_list_contains<COIN_TESTS>(&deny_list, @200), 0);
coin::deny_list_remove(&mut deny_list, &mut deny_cap, @200, scenario.ctx());
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @200), 0);
test_scenario::return_shared(deny_list);
};
transfer::public_freeze_object(deny_cap);
scenario.end();
}


#[test]
fun address_is_frozen_with_arbitrary_types() {
fun deny_list_double_add() {
let mut scenario = test_scenario::begin(@0);
deny_list::create_for_test(scenario.ctx());
scenario.next_tx(TEST_ADDR);

let witness = COIN_TESTS {};
let (treasury, mut deny_cap, metadata) = coin::create_regulated_currency(
witness,
6,
b"COIN_TESTS",
b"coin_name",
b"description",
option::some(url::new_unsafe_from_bytes(b"icon_url")),
scenario.ctx(),
);
transfer::public_freeze_object(metadata);
transfer::public_freeze_object(treasury);
{
// test freezing an address
scenario.next_tx(TEST_ADDR);
let mut deny_list: deny_list::DenyList = scenario.take_shared();
assert!(!coin::deny_list_contains<COIN_TESTS>(&deny_list, @100), 0);
coin::deny_list_add(&mut deny_list, &mut deny_cap, @100, scenario.ctx());
coin::deny_list_add(&mut deny_list, &mut deny_cap, @100, scenario.ctx());
assert!(coin::deny_list_contains<COIN_TESTS>(&deny_list, @100), 0);
test_scenario::return_shared(deny_list);
};
transfer::public_freeze_object(deny_cap);
scenario.end();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

#[test_only]
module sui::deny_list_tests {
use sui::deny_list;
use sui::test_scenario;
use std::type_name;

public struct X()

#[test, expected_failure(abort_code = sui::deny_list::EInvalidAddress)]
fun add_zero() {
let mut ctx = tx_context::dummy();
let mut dl = deny_list::new_for_testing(&mut ctx);
let ty = type_name::into_string(type_name::get_with_original_ids<X>()).into_bytes();
dl.add(1, ty, deny_list::reserved_addresses()[0]); // should error
abort 0 // should not be reached
}

#[test, expected_failure(abort_code = sui::deny_list::EInvalidAddress)]
fun remove_zero() {
let mut ctx = tx_context::dummy();
let mut dl = deny_list::new_for_testing(&mut ctx);
let ty = type_name::into_string(type_name::get_with_original_ids<X>()).into_bytes();
dl.add(1, ty, deny_list::reserved_addresses()[1]); // should error
abort 0 // should not be reached
}

#[test]
fun contains_zero () {
let mut scenario = test_scenario::begin(@0);
deny_list::create_for_test(scenario.ctx());
scenario.next_tx(@0);
let dl: deny_list::DenyList = scenario.take_shared();
let ty = type_name::into_string(type_name::get_with_original_ids<X>()).into_bytes();
let reserved = deny_list::reserved_addresses();
let mut i = 0;
let n = reserved.length();
while (i < n) {
assert!(!dl.contains(1, ty, reserved[i]), 0);
i = i + 1;
};
test_scenario::return_shared(dl);
scenario.end();
}

}

0 comments on commit a5d9b06

Please sign in to comment.