Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit aefbebe

Browse files
authored
Governance: Multiple instructions per proposal transaction (#2833)
* feat: support multiple instructions per proposal instruction * chore: rename instruction to transaction * chore: rename ProposalInstruction to ProposalTransaction * chore: rename instruction to transaction * chore: rename InstructionExecutionStatus to TransactionExecutionStatus * chore: rename proposal instruction to proposal transaction * chore: make clippy happy * chore: update instruction names to transactions * chore: fix compilation * chore: rename instruction to transaction * chore: rename instruction to transaction * chore rename instruction to transaction Co-authored-by: Jon Cinque [email protected]
1 parent 95f6c4f commit aefbebe

28 files changed

+718
-697
lines changed

governance/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,15 @@ people holding Community (or Council) tokens may vote on the Proposal.
152152
Once the Proposal is "tipped" it either enters the Defeated or Succeeded state. If the vote can't be tipped automatically
153153
during the voting period but still reaches the required Yes vote threshold it can be manually transitioned to Succeeded state
154154
using FinalizeVote instruction.
155-
Once all Proposal instructions are executed the Proposal enters Completed state.
155+
Once all Proposal transactions are executed the Proposal enters Completed state.
156156

157157
In the Executing state an instruction can be run by any one at any time after the `instruction_hold_up_time` period has
158158
transpired.
159159

160-
### ProposalInstruction
160+
### ProposalTransaction
161161

162-
A Proposal can have multiple Proposal Instructions, and they run independently of each other.
163-
These contain the actual data for an instruction, and how long after the voting phase a user must wait before they can
162+
A Proposal can have multiple Proposal Transactions with multiple instructions each, and they run independently of each other.
163+
These contain the actual data for instructions, and how long after the voting phase a user must wait before they can
164164
be executed.
165165

166166
### Voting Dynamics

governance/chat/program/tests/program_test/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ impl GovernanceChatProgramTest {
181181
let governance_config = GovernanceConfig {
182182
min_community_tokens_to_create_proposal: 5,
183183
min_council_tokens_to_create_proposal: 2,
184-
min_instruction_hold_up_time: 10,
184+
min_transaction_hold_up_time: 10,
185185
max_voting_time: 10,
186186
vote_threshold_percentage: VoteThresholdPercentage::YesVote(60),
187187
vote_weight_source: spl_governance::state::enums::VoteWeightSource::Deposit,

governance/program/src/error.rs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ pub enum GovernanceError {
5151
#[error("Invalid Realm for TokenOwnerRecord")]
5252
InvalidRealmForTokenOwnerRecord,
5353

54-
/// Invalid Proposal for ProposalInstruction
55-
#[error("Invalid Proposal for ProposalInstruction")]
56-
InvalidProposalForProposalInstruction,
54+
/// Invalid Proposal for ProposalTransaction,
55+
#[error("Invalid Proposal for ProposalTransaction,")]
56+
InvalidProposalForProposalTransaction,
5757

5858
/// Invalid Signatory account address
5959
#[error("Invalid Signatory account address")]
@@ -102,33 +102,33 @@ pub enum GovernanceError {
102102
/// Invalid Proposal state
103103
#[error("Invalid Proposal state")]
104104
InvalidProposalState,
105-
/// Invalid State: Can't edit instructions
106-
#[error("Invalid State: Can't edit instructions")]
107-
InvalidStateCannotEditInstructions,
105+
/// Invalid State: Can't edit transactions
106+
#[error("Invalid State: Can't edit transactions")]
107+
InvalidStateCannotEditTransactions,
108108

109-
/// Invalid State: Can't execute instruction
110-
#[error("Invalid State: Can't execute instruction")]
111-
InvalidStateCannotExecuteInstruction,
109+
/// Invalid State: Can't execute transaction
110+
#[error("Invalid State: Can't execute transaction")]
111+
InvalidStateCannotExecuteTransaction,
112112

113-
/// Can't execute instruction within its hold up time
114-
#[error("Can't execute instruction within its hold up time")]
115-
CannotExecuteInstructionWithinHoldUpTime,
113+
/// Can't execute transaction within its hold up time
114+
#[error("Can't execute transaction within its hold up time")]
115+
CannotExecuteTransactionWithinHoldUpTime,
116116

117-
/// Instruction already executed
118-
#[error("Instruction already executed")]
119-
InstructionAlreadyExecuted,
117+
/// Transaction already executed
118+
#[error("Transaction already executed")]
119+
TransactionAlreadyExecuted,
120120

121-
/// Invalid Instruction index
122-
#[error("Invalid Instruction index")]
123-
InvalidInstructionIndex,
121+
/// Invalid Transaction index
122+
#[error("Invalid Transaction index")]
123+
InvalidTransactionIndex,
124124

125-
/// Instruction hold up time is below the min specified by Governance
126-
#[error("Instruction hold up time is below the min specified by Governance")]
127-
InstructionHoldUpTimeBelowRequiredMin,
125+
/// Transaction hold up time is below the min specified by Governance
126+
#[error("Transaction hold up time is below the min specified by Governance")]
127+
TransactionHoldUpTimeBelowRequiredMin,
128128

129-
/// Instruction at the given index for the Proposal already exists
130-
#[error("Instruction at the given index for the Proposal already exists")]
131-
InstructionAlreadyExists,
129+
/// Transaction at the given index for the Proposal already exists
130+
#[error("Transaction at the given index for the Proposal already exists")]
131+
TransactionAlreadyExists,
132132

133133
/// Invalid State: Can't sign off
134134
#[error("Invalid State: Can't sign off")]
@@ -262,9 +262,9 @@ pub enum GovernanceError {
262262
#[error("Governance PDA must sign")]
263263
GovernancePdaMustSign,
264264

265-
/// Instruction already flagged with error
266-
#[error("Instruction already flagged with error")]
267-
InstructionAlreadyFlaggedWithError,
265+
/// Transaction already flagged with error
266+
#[error("Transaction already flagged with error")]
267+
TransactionAlreadyFlaggedWithError,
268268

269269
/// Invalid Realm for Governance
270270
#[error("Invalid Realm for Governance")]

governance/program/src/instruction.rs

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ use crate::{
1010
native_treasury::get_native_treasury_address,
1111
program_metadata::get_program_metadata_address,
1212
proposal::{get_proposal_address, VoteType},
13-
proposal_instruction::{get_proposal_instruction_address, InstructionData},
14-
realm::{
15-
get_governing_token_holding_address, get_realm_address, RealmConfigArgs,
16-
SetRealmAuthorityAction,
17-
},
13+
proposal_transaction::{get_proposal_transaction_address, InstructionData},
14+
realm::SetRealmAuthorityAction,
15+
realm::{get_governing_token_holding_address, get_realm_address, RealmConfigArgs},
1816
realm_config::get_realm_config_address,
1917
signatory_record::get_signatory_record_address,
2018
token_owner_record::get_token_owner_record_address,
@@ -154,7 +152,7 @@ pub enum GovernanceInstruction {
154152
transfer_upgrade_authority: bool,
155153
},
156154

157-
/// Creates Proposal account for Instructions that will be executed at some point in the future
155+
/// Creates Proposal account for Transactions which will be executed at some point in the future
158156
///
159157
/// 0. `[]` Realm account the created Proposal belongs to
160158
/// 1. `[writable]` Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_index]
@@ -188,7 +186,7 @@ pub enum GovernanceInstruction {
188186
#[allow(dead_code)]
189187
/// Indicates whether the proposal has the deny option
190188
/// A proposal without the rejecting option is a non binding survey
191-
/// Only proposals with the rejecting option can have executable instructions
189+
/// Only proposals with the rejecting option can have executable transactions
192190
use_deny_option: bool,
193191
},
194192

@@ -220,42 +218,42 @@ pub enum GovernanceInstruction {
220218
signatory: Pubkey,
221219
},
222220

223-
/// Inserts an instruction for the Proposal at the given index position
224-
/// New Instructions must be inserted at the end of the range indicated by Proposal instructions_next_index
225-
/// If an Instruction replaces an existing Instruction at a given index then the old one must be removed using RemoveInstruction first
221+
/// Inserts Transaction with a set of instructions for the Proposal at the given index position
222+
/// New Transaction must be inserted at the end of the range indicated by Proposal transactions_next_index
223+
/// If a Transaction replaces an existing Transaction at a given index then the old one must be removed using RemoveTransaction first
226224
227225
/// 0. `[]` Governance account
228226
/// 1. `[writable]` Proposal account
229227
/// 2. `[]` TokenOwnerRecord account of the Proposal owner
230228
/// 3. `[signer]` Governance Authority (Token Owner or Governance Delegate)
231-
/// 4. `[writable]` ProposalInstruction account. PDA seeds: ['governance',proposal,index]
229+
/// 4. `[writable]` ProposalTransaction, account. PDA seeds: ['governance',proposal,index]
232230
/// 5. `[signer]` Payer
233231
/// 6. `[]` System program
234232
/// 7. `[]` Rent sysvar
235-
InsertInstruction {
233+
InsertTransaction {
236234
#[allow(dead_code)]
237-
/// The index of the option the instruction is for
235+
/// The index of the option the transaction is for
238236
option_index: u16,
239237
#[allow(dead_code)]
240-
/// Instruction index to be inserted at.
238+
/// Transaction index to be inserted at.
241239
index: u16,
242240
#[allow(dead_code)]
243241
/// Waiting time (in seconds) between vote period ending and this being eligible for execution
244242
hold_up_time: u32,
245243

246244
#[allow(dead_code)]
247-
/// Instruction Data
248-
instruction: InstructionData,
245+
/// Instructions Data
246+
instructions: Vec<InstructionData>,
249247
},
250248

251-
/// Removes instruction from the Proposal
249+
/// Removes Transaction from the Proposal
252250
///
253251
/// 0. `[writable]` Proposal account
254252
/// 1. `[]` TokenOwnerRecord account of the Proposal owner
255253
/// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate)
256-
/// 3. `[writable]` ProposalInstruction account
257-
/// 4. `[writable]` Beneficiary Account which would receive lamports from the disposed ProposalInstruction account
258-
RemoveInstruction,
254+
/// 3. `[writable]` ProposalTransaction, account
255+
/// 4. `[writable]` Beneficiary Account which would receive lamports from the disposed ProposalTransaction account
256+
RemoveTransaction,
259257

260258
/// Cancels Proposal by changing its state to Canceled
261259
///
@@ -276,8 +274,8 @@ pub enum GovernanceInstruction {
276274
SignOffProposal,
277275

278276
/// Uses your voter weight (deposited Community or Council tokens) to cast a vote on a Proposal
279-
/// By doing so you indicate you approve or disapprove of running the Proposal set of instructions
280-
/// If you tip the consensus then the instructions can begin to be run after their hold up time
277+
/// By doing so you indicate you approve or disapprove of running the Proposal set of transactions
278+
/// If you tip the consensus then the transactions can begin to be run after their hold up time
281279
///
282280
/// 0. `[]` Realm account
283281
/// 1. `[]` Governance account
@@ -328,16 +326,16 @@ pub enum GovernanceInstruction {
328326
/// It's required only when Proposal is still being voted on
329327
RelinquishVote,
330328

331-
/// Executes an instruction in the Proposal
329+
/// Executes a Transaction in the Proposal
332330
/// Anybody can execute transaction once Proposal has been voted Yes and transaction_hold_up time has passed
333-
/// The actual instruction being executed will be signed by Governance PDA the Proposal belongs to
331+
/// The actual transaction being executed will be signed by Governance PDA the Proposal belongs to
334332
/// For example to execute Program upgrade the ProgramGovernance PDA would be used as the singer
335333
///
336334
/// 0. `[writable]` Proposal account
337-
/// 1. `[writable]` ProposalInstruction account you wish to execute
335+
/// 1. `[writable]` ProposalTransaction account you wish to execute
338336
/// 2. `[]` Clock sysvar
339-
/// 3+ Any extra accounts that are part of the instruction, in order
340-
ExecuteInstruction,
337+
/// 3+ Any extra accounts that are part of the transaction, in order
338+
ExecuteTransaction,
341339

342340
/// Creates Mint Governance account which governs a mint
343341
///
@@ -401,17 +399,17 @@ pub enum GovernanceInstruction {
401399
config: GovernanceConfig,
402400
},
403401

404-
/// Flags an instruction and its parent Proposal with error status
405-
/// It can be used by Proposal owner in case the instruction is permanently broken and can't be executed
402+
/// Flags a transaction and its parent Proposal with error status
403+
/// It can be used by Proposal owner in case the transaction is permanently broken and can't be executed
406404
/// Note: This instruction is a workaround because currently it's not possible to catch errors from CPI calls
407405
/// and the Governance program has no way to know when instruction failed and flag it automatically
408406
///
409407
/// 0. `[writable]` Proposal account
410408
/// 1. `[]` TokenOwnerRecord account of the Proposal owner
411409
/// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate)
412-
/// 3. `[writable]` ProposalInstruction account to flag
410+
/// 3. `[writable]` ProposalTransaction account to flag
413411
/// 4. `[]` Clock sysvar
414-
FlagInstructionError,
412+
FlagTransactionError,
415413

416414
/// Sets new Realm authority
417415
///
@@ -1154,9 +1152,9 @@ pub fn cancel_proposal(
11541152
}
11551153
}
11561154

1157-
/// Creates InsertInstruction instruction
1155+
/// Creates InsertTransaction instruction
11581156
#[allow(clippy::too_many_arguments)]
1159-
pub fn insert_instruction(
1157+
pub fn insert_transaction(
11601158
program_id: &Pubkey,
11611159
// Accounts
11621160
governance: &Pubkey,
@@ -1168,9 +1166,9 @@ pub fn insert_instruction(
11681166
option_index: u16,
11691167
index: u16,
11701168
hold_up_time: u32,
1171-
instruction: InstructionData,
1169+
instructions: Vec<InstructionData>,
11721170
) -> Instruction {
1173-
let proposal_instruction_address = get_proposal_instruction_address(
1171+
let proposal_transaction_address = get_proposal_transaction_address(
11741172
program_id,
11751173
proposal,
11761174
&option_index.to_le_bytes(),
@@ -1182,17 +1180,17 @@ pub fn insert_instruction(
11821180
AccountMeta::new(*proposal, false),
11831181
AccountMeta::new_readonly(*token_owner_record, false),
11841182
AccountMeta::new_readonly(*governance_authority, true),
1185-
AccountMeta::new(proposal_instruction_address, false),
1183+
AccountMeta::new(proposal_transaction_address, false),
11861184
AccountMeta::new(*payer, true),
11871185
AccountMeta::new_readonly(system_program::id(), false),
11881186
AccountMeta::new_readonly(sysvar::rent::id(), false),
11891187
];
11901188

1191-
let instruction = GovernanceInstruction::InsertInstruction {
1189+
let instruction = GovernanceInstruction::InsertTransaction {
11921190
option_index,
11931191
index,
11941192
hold_up_time,
1195-
instruction,
1193+
instructions,
11961194
};
11971195

11981196
Instruction {
@@ -1202,25 +1200,25 @@ pub fn insert_instruction(
12021200
}
12031201
}
12041202

1205-
/// Creates RemoveInstruction instruction
1206-
pub fn remove_instruction(
1203+
/// Creates RemoveTransaction instruction
1204+
pub fn remove_transaction(
12071205
program_id: &Pubkey,
12081206
// Accounts
12091207
proposal: &Pubkey,
12101208
token_owner_record: &Pubkey,
12111209
governance_authority: &Pubkey,
1212-
proposal_instruction: &Pubkey,
1210+
proposal_transaction: &Pubkey,
12131211
beneficiary: &Pubkey,
12141212
) -> Instruction {
12151213
let accounts = vec![
12161214
AccountMeta::new(*proposal, false),
12171215
AccountMeta::new_readonly(*token_owner_record, false),
12181216
AccountMeta::new_readonly(*governance_authority, true),
1219-
AccountMeta::new(*proposal_instruction, false),
1217+
AccountMeta::new(*proposal_transaction, false),
12201218
AccountMeta::new(*beneficiary, false),
12211219
];
12221220

1223-
let instruction = GovernanceInstruction::RemoveInstruction {};
1221+
let instruction = GovernanceInstruction::RemoveTransaction {};
12241222

12251223
Instruction {
12261224
program_id: *program_id,
@@ -1229,27 +1227,27 @@ pub fn remove_instruction(
12291227
}
12301228
}
12311229

1232-
/// Creates ExecuteInstruction instruction
1233-
pub fn execute_instruction(
1230+
/// Creates ExecuteTransaction instruction
1231+
pub fn execute_transaction(
12341232
program_id: &Pubkey,
12351233
// Accounts
12361234
governance: &Pubkey,
12371235
proposal: &Pubkey,
1238-
proposal_instruction: &Pubkey,
1236+
proposal_transaction: &Pubkey,
12391237
instruction_program_id: &Pubkey,
12401238
instruction_accounts: &[AccountMeta],
12411239
) -> Instruction {
12421240
let mut accounts = vec![
12431241
AccountMeta::new_readonly(*governance, false),
12441242
AccountMeta::new(*proposal, false),
1245-
AccountMeta::new(*proposal_instruction, false),
1243+
AccountMeta::new(*proposal_transaction, false),
12461244
AccountMeta::new_readonly(sysvar::clock::id(), false),
12471245
AccountMeta::new_readonly(*instruction_program_id, false),
12481246
];
12491247

12501248
accounts.extend_from_slice(instruction_accounts);
12511249

1252-
let instruction = GovernanceInstruction::ExecuteInstruction {};
1250+
let instruction = GovernanceInstruction::ExecuteTransaction {};
12531251

12541252
Instruction {
12551253
program_id: *program_id,
@@ -1277,24 +1275,24 @@ pub fn set_governance_config(
12771275
}
12781276
}
12791277

1280-
/// Creates FlagInstructionError instruction
1281-
pub fn flag_instruction_error(
1278+
/// Creates FlagTransactionError instruction
1279+
pub fn flag_transaction_error(
12821280
program_id: &Pubkey,
12831281
// Accounts
12841282
proposal: &Pubkey,
12851283
token_owner_record: &Pubkey,
12861284
governance_authority: &Pubkey,
1287-
proposal_instruction: &Pubkey,
1285+
proposal_transaction: &Pubkey,
12881286
) -> Instruction {
12891287
let accounts = vec![
12901288
AccountMeta::new(*proposal, false),
12911289
AccountMeta::new_readonly(*token_owner_record, false),
12921290
AccountMeta::new_readonly(*governance_authority, true),
1293-
AccountMeta::new(*proposal_instruction, false),
1291+
AccountMeta::new(*proposal_transaction, false),
12941292
AccountMeta::new_readonly(sysvar::clock::id(), false),
12951293
];
12961294

1297-
let instruction = GovernanceInstruction::FlagInstructionError {};
1295+
let instruction = GovernanceInstruction::FlagTransactionError {};
12981296

12991297
Instruction {
13001298
program_id: *program_id,

0 commit comments

Comments
 (0)