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

Quorum Upgrade V2 WIP #62

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
14 changes: 14 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/quorum_upgrade_policy.move
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
/// - the creation and usage of a `Ballot` to vote for the upgrade is also being
/// discussed. The ballot will be transferable and an easy way to relate to a proposal
module quorum_upgrade_policy::quorum_upgrade_policy {
use quorum_upgrade_policy::quorum_upgrade_v2;
use sui::event;
use sui::package::{Self, UpgradeCap, UpgradeTicket, UpgradeReceipt};
use sui::vec_set::{Self, VecSet};
Expand Down Expand Up @@ -246,6 +247,19 @@ module quorum_upgrade_policy::quorum_upgrade_policy {
}
}


public fun migrate_quorum_to_v2(cap: QuorumUpgradeCap, ctx: &mut TxContext) {
let QuorumUpgradeCap {
id,
upgrade_cap,
required_votes,
voters,
voter_caps: _voter_caps,
} = cap;
quorum_upgrade_policy_v2::new(upgrade_cap, required_votes, voters, ctx);
id.delete();
}

/// Propose an upgrade.
/// The `digest` of the proposed upgrade is provided to identify the upgrade.
/// The proposer is the sender of the transaction and must be the signer
Expand Down
102 changes: 102 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/quorum_upgrade_v2.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

module quorum_upgrade_policy::quorum_upgrade_v2;

use sui::event;
use sui::package::{Self, UpgradeCap, UpgradeTicket, UpgradeReceipt};
use sui::vec_set::{Self, VecSet};

public struct QuorumUpgrade has key, store {
id: UID,
upgrade_cap: UpgradeCap,
required_votes: u64,
voters: VecSet<address>,
}

public fun new(
upgrade_cap: UpgradeCap,
required_votes: u64,
voters: VecSet<address>,
ctx: &mut TxContext,
) {
let id = object::new(ctx);
let quorum_upgrade = QuorumUpgrade {
id,
upgrade_cap,
required_votes,
voters,
};
transfer::share_object(quorum_upgrade);
}

public(package) fun add_voter(
quorum_upgrade: &mut QuorumUpgrade,
voter: address,
new_required_votes: u64,
) {
quorum_upgrade.voters.insert(voter);
quorum_upgrade.required_votes = new_required_votes;
}

public(package) fun remove_voter(
quorum_upgrade: &mut QuorumUpgrade,
voter: address,
new_required_votes: u64,
) {
quorum_upgrade.voters.remove(&voter);
quorum_upgrade.required_votes = new_required_votes;
}

public(package) fun update_required_votes(
quorum_upgrade: &mut QuorumUpgrade,
new_required_votes: u64,
) {
quorum_upgrade.required_votes = new_required_votes;
}

public(package) fun replace_voter(
quorum_upgrade: &mut QuorumUpgrade,
old_voter: address,
new_voter: address,
) {
quorum_upgrade.voters.remove(&old_voter);
quorum_upgrade.voters.insert(new_voter);
}

public(package) fun relinquish_quorum(quorum_upgrade: QuorumUpgrade, new_owner: address) {
let QuorumUpgrade {
id,
upgrade_cap,
required_votes: _required_votes,
voters: _voters,
} = quorum_upgrade;

id.delete();

transfer::public_transfer(upgrade_cap, new_owner);
}

public fun voters(quorum_upgrade: &QuorumUpgrade): &VecSet<address> {
&quorum_upgrade.voters
}

public fun required_votes(quorum_upgrade: &QuorumUpgrade): u64 {
quorum_upgrade.required_votes
}

public fun commit_upgrade(quorum_upgrade: &mut QuorumUpgrade, receipt: UpgradeReceipt) {
package::commit_upgrade(&mut quorum_upgrade.upgrade_cap, receipt)
}

public(package) fun authorize_upgrade(
quorum_upgrade: &mut QuorumUpgrade,
digest: vector<u8>,
): UpgradeTicket {
let policy = package::upgrade_policy(&quorum_upgrade.upgrade_cap);
package::authorize_upgrade(
&mut quorum_upgrade.upgrade_cap,
policy,
digest,
)
}
27 changes: 27 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/types/add_voter.move
Bridgerz marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module quorum_upgrade_policy::add_voter;

use quorum_upgrade_policy::proposal::Proposal;
use quorum_upgrade_policy::quorum_upgrade_v2::QuorumUpgrade;

public struct AddVoter has copy, drop {
voter: address,
new_required_votes: u64,
}

// Does/can validation happen here on the provided params
public fun new(voter: address, new_required_votes: u64): AddVoter {
AddVoter { voter, new_required_votes }
}

public fun execute(proposal: Proposal<AddVoter>, quorum_upgrade: &mut QuorumUpgrade) {
assert!(!quorum_upgrade.voters().contains(&proposal.data().voter));

let AddVoter {
voter,
new_required_votes,
} = proposal.data();

quorum_upgrade.add_voter(voter, new_required_votes);

proposal.execute(quorum_upgrade)
}
93 changes: 93 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/types/proposal.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
module quorum_upgrade_policy::proposal;

use quorum_upgrade_policy::quorum_upgrade_v2::QuorumUpgrade;
use sui::vec_set::{Self, VecSet};

public struct Proposal<T> has key, store {
id: UID,
creator: address,
quorum_upgrade: ID,
votes: VecSet<address>,
data: T,
}

// hot potato object use to cast vote
public struct Vote {
voter: address,
proposal_id: ID,
}

public fun new<T: store>(quorum_upgrade: &QuorumUpgrade, data: T, ctx: &mut TxContext) {
// only voters can create proposal
assert!(quorum_upgrade.voters().contains(&ctx.sender()));

let proposal = Proposal {
id: object::new(ctx),
creator: ctx.sender(),
quorum_upgrade: object::id(quorum_upgrade),
votes: vec_set::empty(),
data,
};
transfer::share_object(proposal);
}

public fun vote<T>(proposal: &mut Proposal<T>, vote: Vote) {
let Vote { voter, proposal_id } = vote;
assert!(!proposal.votes.contains(&voter));
assert!(proposal.id.to_inner() == proposal_id);
proposal.votes.insert(voter);
}

public fun create_vote<T>(
quorum_upgrade: &QuorumUpgrade,
proposal: &Proposal<T>,
ctx: &mut TxContext,
): Vote {
assert!(quorum_upgrade.voters().contains(&ctx.sender()));
Vote {
voter: ctx.sender(),
proposal_id: proposal.id.to_inner(),
}
}

public fun quorum_reached<T>(proposal: &Proposal<T>, quorum_upgrade: &QuorumUpgrade): bool {
let current_votes = proposal.votes.size();
let required_votes = quorum_upgrade.required_votes();
current_votes >= required_votes
}

public fun delete_proposal_by_creator<T: drop>(proposal: Proposal<T>, ctx: &mut TxContext) {
assert!(proposal.creator == ctx.sender());
proposal.delete();
}

public(package) fun execute<T: drop>(proposal: Proposal<T>, quorum_upgrade: &QuorumUpgrade) {
assert!(proposal.quorum_reached(quorum_upgrade));
assert!(proposal.quorum_upgrade == object::id(quorum_upgrade));
proposal.delete();
}

public(package) fun delete<T: drop>(proposal: Proposal<T>) {
let Proposal<T> {
id,
creator: _creator,
quorum_upgrade: _quorum_upgrade,
votes: _votes,
data: _data,
} = proposal;
id.delete();
}

// read functions

public fun data<T: copy>(proposal: &Proposal<T>): T {
Bridgerz marked this conversation as resolved.
Show resolved Hide resolved
proposal.data
}

public fun quorum_upgrade<T: copy>(proposal: &Proposal<T>): ID {
Bridgerz marked this conversation as resolved.
Show resolved Hide resolved
proposal.quorum_upgrade
}

public fun votes<T: copy>(proposal: &Proposal<T>): &VecSet<address> {
&proposal.votes
}
23 changes: 23 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/types/relinquish_quorum.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module quorum_upgrade_policy::relinquish_quorum;

use quorum_upgrade_policy::proposal::Proposal;
use quorum_upgrade_policy::quorum_upgrade_v2::QuorumUpgrade;

public struct RelinquishQuorum has copy, drop {
new_owner: address,
}

// Does/can validation happen here on the provided params
public fun new(new_owner: address): RelinquishQuorum {
RelinquishQuorum { new_owner }
}

public fun execute(proposal: Proposal<RelinquishQuorum>, quorum_upgrade: QuorumUpgrade) {
let RelinquishQuorum {
new_owner,
} = proposal.data();

quorum_upgrade.relinquish_quorum(new_owner);

proposal.delete();
}
28 changes: 28 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/types/remove_voter.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module quorum_upgrade_policy::remove_voter;

use quorum_upgrade_policy::proposal::Proposal;
use quorum_upgrade_policy::quorum_upgrade_v2::QuorumUpgrade;

public struct RemoveVoter has copy, drop {
voter: address,
new_required_votes: u64,
}

// Does/can validation happen here on the provided params
public fun new(voter: address, new_required_votes: u64): RemoveVoter {
RemoveVoter { voter, new_required_votes }
}

public fun execute(proposal: Proposal<RemoveVoter>, quorum_upgrade: &mut QuorumUpgrade) {
assert!(quorum_upgrade.voters().contains(&proposal.data().voter));
assert!(quorum_upgrade.voters().size() - 1 >= quorum_upgrade.required_votes());

let RemoveVoter {
voter,
new_required_votes,
} = proposal.data();

proposal.execute(quorum_upgrade);

quorum_upgrade.remove_voter(voter, new_required_votes);
}
28 changes: 28 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/types/replace_voter.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module quorum_upgrade_policy::replace_voter;

use quorum_upgrade_policy::proposal::Proposal;
use quorum_upgrade_policy::quorum_upgrade_v2::QuorumUpgrade;

public struct ReplaceVoter has copy, drop {
new_voter: address,
old_voter: address,
}

// Does/can validation happen here on the provided params
public fun new(new_voter: address, old_voter: address): ReplaceVoter {
ReplaceVoter { new_voter, old_voter }
}

public fun execute(proposal: Proposal<ReplaceVoter>, quorum_upgrade: &mut QuorumUpgrade) {
assert!(quorum_upgrade.voters().contains(&proposal.data().old_voter));
assert!(!quorum_upgrade.voters().contains(&proposal.data().new_voter));

let ReplaceVoter {
new_voter,
old_voter,
} = proposal.data();

proposal.execute(quorum_upgrade);
Bridgerz marked this conversation as resolved.
Show resolved Hide resolved

quorum_upgrade.replace_voter(old_voter, new_voter);
}
20 changes: 20 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/types/update_quorum.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module quorum_upgrade_policy::quorum_change;

use quorum_upgrade_policy::proposal::Proposal;
use quorum_upgrade_policy::quorum_upgrade_v2::QuorumUpgrade;

public struct UpdateQuorum has copy, drop {
new_required_votes: u64,
}

public fun new(new_required_votes: u64): UpdateQuorum {
UpdateQuorum { new_required_votes }
}

public fun execute(proposal: Proposal<UpdateQuorum>, quorum_upgrade: &mut QuorumUpgrade) {
let new_required_votes = proposal.data().new_required_votes;

proposal.execute(quorum_upgrade);

quorum_upgrade.update_required_votes(new_required_votes);
}
23 changes: 23 additions & 0 deletions upgrade_policy/quorum_upgrade/sources/types/upgrade.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module quorum_upgrade_policy::upgrade;

use quorum_upgrade_policy::proposal::Proposal;
use quorum_upgrade_policy::quorum_upgrade_v2::QuorumUpgrade;
use sui::package::UpgradeTicket;

public struct Upgrade has copy, drop {
digest: vector<u8>,
}

public fun new(digest: vector<u8>): Upgrade {
Upgrade { digest }
}

public fun execute(proposal: Proposal<Upgrade>, quorum_upgrade: &mut QuorumUpgrade): UpgradeTicket {
let digest = proposal.data().digest;

proposal.execute(quorum_upgrade);

let ticket = quorum_upgrade.authorize_upgrade(digest);

ticket
}
Loading