Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(version_control,axelar_gateway)!: version control update to axelar_gateway #208

Merged
merged 8 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tough-buttons-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@axelar-network/axelar-cgp-sui': minor
---

Add a query for version on version_control, change CreatorCap to OwnerCap and allow owner to set allowed functions in gateway
79 changes: 53 additions & 26 deletions move/axelar_gateway/sources/gateway.move
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use axelar_gateway::bytes32::{Self, Bytes32};
use axelar_gateway::channel::{Channel, ApprovedMessage};
use axelar_gateway::gateway_v0::{Self, Gateway_v0};
use axelar_gateway::message_ticket::{Self, MessageTicket};
use axelar_gateway::owner_cap::{Self, OwnerCap};
use axelar_gateway::weighted_signers;
use std::ascii::{Self, String};
use sui::clock::Clock;
Expand All @@ -62,30 +63,21 @@ public struct Gateway has key {
inner: Versioned,
}

// ------------
// Capabilities
// ------------
public struct CreatorCap has key, store {
id: UID,
}

// -----
// Setup
// -----

/// Init the module by giving a CreatorCap to the sender to allow a full
/// Init the module by giving a OwnerCap to the sender to allow a full
/// `setup`.
fun init(ctx: &mut TxContext) {
let cap = CreatorCap {
id: object::new(ctx),
};
let cap = owner_cap::create(ctx);

transfer::transfer(cap, ctx.sender());
transfer::public_transfer(cap, ctx.sender());
}

/// Setup the module by creating a new Gateway object.
entry fun setup(
cap: CreatorCap,
_: &OwnerCap,
operator: address,
domain_separator: address,
minimum_rotation_delay: u64,
Expand All @@ -94,9 +86,6 @@ entry fun setup(
clock: &Clock,
ctx: &mut TxContext,
) {
let CreatorCap { id } = cap;
id.delete();

let inner = versioned::create(
VERSION,
gateway_v0::new(
Expand Down Expand Up @@ -185,6 +174,14 @@ entry fun rotate_signers(
)
}

entry fun allow_function(self: &mut Gateway, _: &OwnerCap, version: u64, function_name: String) {
self.value_mut!(b"allow_function").allow_function(version, function_name);
}

entry fun disallow_function(self: &mut Gateway, _: &OwnerCap, version: u64, function_name: String) {
self.value_mut!(b"disallow_function").disallow_function(version, function_name);
}

// ----------------
// Public Functions
// ----------------
Expand Down Expand Up @@ -274,6 +271,8 @@ fun version_control(): VersionControl {
b"is_message_executed",
b"take_approved_message",
b"send_message",
b"allow_function",
b"disallow_function",
].map!(|function_name| function_name.to_ascii_string()),
])
}
Expand Down Expand Up @@ -338,6 +337,8 @@ fun dummy(ctx: &mut TxContext): Gateway {
b"is_message_executed",
b"take_approved_message",
b"send_message",
b"allow_function",
b"disallow_function",
b"",
].map!(|function_name| function_name.to_ascii_string()),
]),
Expand Down Expand Up @@ -376,7 +377,7 @@ fun test_init() {
init(ts.ctx());
ts.next_tx(@0x0);

let creator_cap = ts.take_from_sender<CreatorCap>();
let creator_cap = ts.take_from_sender<OwnerCap>();
ts.return_to_sender(creator_cap);
ts.end();
}
Expand All @@ -394,14 +395,12 @@ fun test_setup() {
let timestamp = rng.generate_u64();
clock.increment_for_testing(timestamp);

let creator_cap = CreatorCap {
id: object::new(ctx),
};
let owner_cap = owner_cap::create(ctx);

let mut scenario = sui::test_scenario::begin(@0x1);

setup(
creator_cap,
&owner_cap,
operator,
domain_separator,
minimum_rotation_delay,
Expand Down Expand Up @@ -451,6 +450,7 @@ fun test_setup() {
assert!(previous_signers_retention == previous_signers_retention_result);

clock.destroy_for_testing();
owner_cap.destroy_for_testing();
scenario.end();
}

Expand All @@ -468,15 +468,13 @@ fun test_setup_remaining_bytes() {
let timestamp = rng.generate_u64();
clock.increment_for_testing(timestamp);

let creator_cap = CreatorCap {
id: object::new(ctx),
};
let owner_cap = owner_cap::create(ctx);

let mut scenario = sui::test_scenario::begin(@0x1);
let mut initial_signers_bytes = bcs::to_bytes(&initial_signers);
initial_signers_bytes.push_back(0);
setup(
creator_cap,
&owner_cap,
operator,
domain_separator,
minimum_rotation_delay,
Expand Down Expand Up @@ -526,6 +524,7 @@ fun test_setup_remaining_bytes() {
assert!(previous_signers_retention == previous_signers_retention_result);

clock.destroy_for_testing();
owner_cap.destroy_for_testing();
scenario.end();
}

Expand Down Expand Up @@ -1052,9 +1051,37 @@ fun test_send_message() {

let gateway = dummy(ctx);
gateway.send_message(message_ticket);

utils::assert_event<events::ContractCall>();

sui::test_utils::destroy(gateway);
channel.destroy();
}

#[test]
fun test_allow_function() {
let ctx = &mut sui::tx_context::dummy();
let mut self = dummy(ctx);
let owner_cap = owner_cap::create(ctx);
let version = 0;
let function_name = b"function_name".to_ascii_string();

self.allow_function(&owner_cap, version, function_name);

sui::test_utils::destroy(self);
owner_cap.destroy_for_testing();
}

#[test]
fun test_disallow_function() {
let ctx = &mut sui::tx_context::dummy();
let mut self = dummy(ctx);
let owner_cap = owner_cap::create(ctx);
let version = 0;
let function_name = b"approve_messages".to_ascii_string();

self.disallow_function(&owner_cap, version, function_name);

sui::test_utils::destroy(self);
owner_cap.destroy_for_testing();
}
23 changes: 23 additions & 0 deletions move/axelar_gateway/sources/types/owner_cap.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module axelar_gateway::owner_cap;

// -----
// Types
// -----
public struct OwnerCap has key, store {
id: UID,
}

public(package) fun create(ctx: &mut TxContext): OwnerCap {
OwnerCap {
id: object::new(ctx),
}
}

/// ---------
/// Test Only
/// ---------
#[test_only]
public(package) fun destroy_for_testing(self: OwnerCap) {
let OwnerCap { id } = self;
id.delete();
}
10 changes: 9 additions & 1 deletion move/axelar_gateway/sources/versioned/gateway_v0.move
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public enum CommandType {
// -----------------
// Package Functions
// -----------------
/// Init the module by giving a CreatorCap to the sender to allow a full
/// Init the module by giving a OwnerCap to the sender to allow a full
/// `setup`.
public(package) fun new(
operator: address,
Expand Down Expand Up @@ -221,6 +221,14 @@ public(package) fun send_message(
);
}

public(package) fun allow_function(self: &mut Gateway_v0, version: u64, function_name: String) {
Foivos marked this conversation as resolved.
Show resolved Hide resolved
self.version_control.allow_function(version, function_name);
}

public(package) fun disallow_function(self: &mut Gateway_v0, version: u64, function_name: String) {
self.version_control.disallow_function(version, function_name);
}

// -----------------
// Private Functions
// -----------------
Expand Down
94 changes: 94 additions & 0 deletions move/version_control/sources/version_control.move
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ use sui::vec_set::{Self, VecSet};
const EFunctionNotSupported: vector<u8> =
b"function is not supported in this version";

#[error]
const EFunctionAlreadyAllowed: vector<u8> =
b"trying to allow a function already allowed on the specified version";

#[error]
const EFunctionAlreadyDisallowed: vector<u8> =
b"trying to disallow a function already disallowed on the specified version";

// -----
// Types
// -----
Expand Down Expand Up @@ -65,6 +73,16 @@ public fun push_back(
);
}

public fun allow_function(self: &mut VersionControl, version: u64, function_name: String) {
assert!(!self.allowed_functions[version].contains(&function_name), EFunctionAlreadyAllowed);
self.allowed_functions[version].insert(function_name);
}

public fun disallow_function(self: &mut VersionControl, version: u64, function_name: String) {
assert!(self.allowed_functions[version].contains(&function_name), EFunctionAlreadyDisallowed);
self.allowed_functions[version].remove(&function_name);
}

/// Call this at the begining of each version controlled function. For example
/// ```
/// public fun do_something(data: &mut DataType) {
Expand All @@ -79,6 +97,11 @@ public fun check(self: &VersionControl, version: u64, function: String) {
);
}

/// Returns the latest valid index in allowed functions.
public fun latest_version(self: &VersionControl): u64 {
self.allowed_functions.length() - 1
}

#[test]
fun test_new() {
let version_control = new(vector[
Expand Down Expand Up @@ -165,3 +188,74 @@ fun test_check_function_not_supported() {
]);
version_control.check(0, b"function_name_2".to_ascii_string());
}

#[test]
fun test_allow_function() {
let version = 0;
let function_name = b"function_name".to_ascii_string();
let mut self = new(vector[
vector[
],
]);

self.allow_function(version, function_name);

sui::test_utils::destroy(self);
}

#[test]
fun test_disallow_function() {
let version = 0;
let function_name = b"function_name".to_ascii_string();
let mut self = new(vector[
vector[
function_name,
],
]);

self.disallow_function(version, function_name);

sui::test_utils::destroy(self);
}

#[test]
#[expected_failure(abort_code = EFunctionAlreadyAllowed)]
fun test_allow_function_already_allowed() {
let version = 0;
let function_name = b"function_name".to_ascii_string();
let mut self = new(vector[
vector[
function_name,
],
]);

self.allow_function(version, function_name);

sui::test_utils::destroy(self);
}

#[test]
#[expected_failure(abort_code = EFunctionAlreadyDisallowed)]
fun test_disallow_function_already_disallowed() {
let version = 0;
let function_name = b"function_name".to_ascii_string();
let mut self = new(vector[
vector[
],
]);

self.disallow_function(version, function_name);

sui::test_utils::destroy(self);
}

#[test]
fun test_latest_function() {
let mut self = new(vector[
vector[],
]);

assert!(self.latest_version() == 0);

sui::test_utils::destroy(self);
}
2 changes: 1 addition & 1 deletion scripts/limits.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ async function prepare(network, keypairs, domainSeparator) {
let result = await publishPackage(client, deployer, 'axelar_gateway');
packageId = result.packageId;
const creatorCap = result.publishTxn.objectChanges.find(
(change) => change.objectType === `${packageId}::gateway::CreatorCap`,
(change) => change.objectType === `${packageId}::gateway::OwnerCap`,
).objectId;
result = await publishPackage(client, deployer, 'relayer_discovery');
const discoveryPackageId = result.packageId;
Expand Down
2 changes: 1 addition & 1 deletion test/axelar-gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('Axelar Gateway', () => {
let result = await publishPackage(client, deployer, 'axelar_gateway');
packageId = result.packageId;
const creatorCap = result.publishTxn.objectChanges.find(
(change) => change.objectType === `${packageId}::gateway::CreatorCap`,
(change) => change.objectType === `${packageId}::gateway::OwnerCap`,
).objectId;
result = await publishPackage(client, deployer, 'relayer_discovery');
const discoveryPackageId = result.packageId;
Expand Down
2 changes: 1 addition & 1 deletion test/its.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe('ITS', () => {
`${deployments.relayer_discovery.packageId}::discovery::RelayerDiscovery`,
),
gasService: findObjectId(deployments.gas_service.publishTxn, `${deployments.gas_service.packageId}::gas_service::GasService`),
creatorCap: findObjectId(deployments.axelar_gateway.publishTxn, 'CreatorCap'),
creatorCap: findObjectId(deployments.axelar_gateway.publishTxn, 'OwnerCap'),
itsOwnerCap: findObjectId(deployments.its.publishTxn, `${deployments.its.packageId}::owner_cap::OwnerCap`),
};
// Mint some coins for tests
Expand Down
2 changes: 1 addition & 1 deletion test/squid.js
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ describe('Squid', () => {
`${deployments.relayer_discovery.packageId}::discovery::RelayerDiscovery`,
),
gasService: findObjectId(deployments.gas_service.publishTxn, `${deployments.gas_service.packageId}::gas_service::GasService`),
creatorCap: findObjectId(deployments.axelar_gateway.publishTxn, 'CreatorCap'),
creatorCap: findObjectId(deployments.axelar_gateway.publishTxn, 'OwnerCap'),
itsOwnerCap: findObjectId(deployments.its.publishTxn, `${deployments.its.packageId}::owner_cap::OwnerCap`),
gateway: findObjectId(deployments.its.publishTxn, `${deployments.axelar_gateway.packageId}::gateway::Gateway`),
};
Expand Down
Loading
Loading