Skip to content

Commit 1c5cad9

Browse files
committed
finalize versioned transactions
1 parent 0e8f7c3 commit 1c5cad9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+6659
-103
lines changed

Cargo.lock

Lines changed: 94 additions & 44 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

governance/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Add deprecated warning for create_mint_governance() and create_token_governance() (it will be removed in v4.0.0)
66
- Add SPL Token 2022 support
7+
- Add VersionedTransaction support for proposals
78

89
## v3.1.1 - 25 Apr 2022
910

governance/program/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ license = "Apache-2.0"
88
edition = "2021"
99

1010
[features]
11+
default = ["custom-heap"]
12+
custom-heap = []
1113
no-entrypoint = []
1214
test-sbf = []
1315

governance/program/src/entrypoint.rs

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Program entrypoint definitions
2-
#![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))]
2+
#![cfg(not(feature = "no-entrypoint"))]
33

44
use {
55
crate::{error::GovernanceError, processor},
@@ -9,6 +9,145 @@ use {
99
},
1010
};
1111

12+
/*
13+
Optimizing Bump Heap Allocation
14+
15+
Objective: Increase available heap memory while maintaining flexibility in program invocation.
16+
17+
1. Initial State: Default 32 KiB Heap
18+
19+
Memory Layout:
20+
0x300000000 0x300008000
21+
| |
22+
v v
23+
[--------------------]
24+
^ ^
25+
| |
26+
VM Lower VM Upper
27+
Boundary Boundary
28+
29+
Default Allocator (Allocates Backwards / Top Down) (Default 32 KiB):
30+
0x300000000 0x300008000
31+
| |
32+
[--------------------]
33+
^
34+
|
35+
Allocation starts here (SAFE)
36+
37+
2. Naive Approach: Increase HEAP_LENGTH to 8 * 32 KiB + Default Allocator
38+
39+
Memory Layout with Increased HEAP_LENGTH:
40+
0x300000000 0x300008000 0x300040000
41+
| | |
42+
v v v
43+
[--------------------|------------------------------------|]
44+
^ ^ ^
45+
| | |
46+
VM Lower VM Upper Allocation starts here
47+
Boundary Boundary (ACCESS VIOLATION!)
48+
49+
Issue: Access violation occurs without requestHeapFrame, requiring it for every transaction.
50+
51+
3. Optimized Solution: Forward Allocation with Flexible Heap Usage
52+
53+
Memory Layout (Same as Naive Approach):
54+
0x300000000 0x300008000 0x300040000
55+
| | |
56+
v v v
57+
[--------------------|------------------------------------|]
58+
^ ^ ^
59+
| | |
60+
VM Lower VM Upper Allocator & VM
61+
Boundary Boundary Heap Limit
62+
63+
Forward Allocator Behavior:
64+
65+
a) Without requestHeapFrame:
66+
0x300000000 0x300008000
67+
| |
68+
[--------------------]
69+
^ ^
70+
| |
71+
VM Lower VM Upper
72+
Boundary Boundary
73+
Allocation
74+
starts here (SAFE)
75+
76+
b) With requestHeapFrame:
77+
0x300000000 0x300008000 0x300040000
78+
| | |
79+
[--------------------|------------------------------------|]
80+
^ ^ ^
81+
| | |
82+
VM Lower | VM Upper
83+
Boundary Boundary
84+
Allocation Allocation continues Maximum allocation
85+
starts here with requestHeapFrame with requestHeapFrame
86+
(SAFE)
87+
88+
Key Advantages:
89+
1. Compatibility: Functions without requestHeapFrame for allocations ≤32 KiB.
90+
2. Extensibility: Supports larger allocations when requestHeapFrame is invoked.
91+
3. Efficiency: Eliminates mandatory requestHeapFrame calls for all transactions.
92+
93+
Conclusion:
94+
The forward allocation strategy offers a robust solution, providing both backward
95+
compatibility for smaller heap requirements and the flexibility to utilize extended
96+
heap space when necessary.
97+
98+
The following allocator is a copy of the bump allocator found in
99+
solana_program::entrypoint and
100+
https://github.com/solana-labs/solana-program-library/blob/master/examples/rust/custom-heap/src/entrypoint.rs
101+
102+
but with changes to its HEAP_LENGTH and its
103+
starting allocation address.
104+
*/
105+
106+
#[cfg(target_os = "solana")]
107+
use {
108+
solana_program::entrypoint::HEAP_START_ADDRESS,
109+
std::{alloc::Layout, mem::size_of, ptr::null_mut, usize},
110+
};
111+
112+
/// Length of the memory region used for program heap.
113+
pub const HEAP_LENGTH: usize = 8 * 32 * 1024;
114+
115+
#[cfg(target_os = "solana")]
116+
struct BumpAllocator;
117+
118+
#[cfg(target_os = "solana")]
119+
unsafe impl std::alloc::GlobalAlloc for BumpAllocator {
120+
#[inline]
121+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
122+
const POS_PTR: *mut usize = HEAP_START_ADDRESS as *mut usize;
123+
const TOP_ADDRESS: usize = HEAP_START_ADDRESS as usize + HEAP_LENGTH;
124+
const BOTTOM_ADDRESS: usize = HEAP_START_ADDRESS as usize + size_of::<*mut u8>();
125+
let mut pos = *POS_PTR;
126+
if pos == 0 {
127+
// First time, set starting position to bottom address
128+
pos = BOTTOM_ADDRESS;
129+
}
130+
// Align the position upwards
131+
pos = (pos + layout.align() - 1) & !(layout.align() - 1);
132+
let next_pos = pos.saturating_add(layout.size());
133+
if next_pos > TOP_ADDRESS {
134+
return null_mut();
135+
}
136+
*POS_PTR = next_pos;
137+
pos as *mut u8
138+
}
139+
140+
#[inline]
141+
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
142+
// I'm a bump allocator, I don't free
143+
}
144+
}
145+
146+
#[cfg(target_os = "solana")]
147+
#[global_allocator]
148+
static A: BumpAllocator = BumpAllocator;
149+
150+
12151
solana_program::entrypoint!(process_instruction);
13152
fn process_instruction(
14153
program_id: &Pubkey,

governance/program/src/error.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ pub enum GovernanceError {
3535
#[error("Governing Token Owner must sign transaction")]
3636
GoverningTokenOwnerMustSign,
3737

38-
/// Governing Token Owner or Delegate must sign transaction
39-
#[error("Governing Token Owner or Delegate must sign transaction")]
38+
/// Governing Token Owner or Delegate must sign transaction
39+
#[error("Governing Token Owner or Delegate must sign transaction")]
4040
GoverningTokenOwnerOrDelegateMustSign, // 505
4141

4242
/// All votes must be relinquished to withdraw governing tokens
@@ -524,6 +524,83 @@ pub enum GovernanceError {
524524
/// Math Overflow
525525
#[error("Mathematical Overflow")]
526526
MathematicalOverflow, // 625
527+
528+
/// Invalid lookup table account owner
529+
#[error("Invalid lookup table account owner")]
530+
InvalidLookupTableAccountOwner, // 626
531+
532+
/// Invalid lookup table accounts key
533+
#[error("Invalid lookup table account key")]
534+
InvalidLookupTableAccountKey, // 627
535+
536+
/// Invalid number of accounts in message
537+
#[error("Invalid number of accounts in message")]
538+
InvalidNumberOfAccountsInMessage, // 628
539+
540+
/// Invalid account found in message
541+
#[error("Invalid account found in message")]
542+
InvalidAccountFoundInMessage, // 629
543+
544+
/// Invalid account signer found in message
545+
#[error("Invalid account signer found in message")]
546+
InvalidAccountSigner, // 630
547+
548+
/// Invalid writeable account found in message
549+
#[error("Invalid writeable account found in message")]
550+
InvalidAccountWriteable, // 631
551+
552+
/// Invalid account found in message
553+
#[error("Invalid writeable account found in message")]
554+
InvalidAccountFound, // 632
555+
556+
/// Account in lookuptable is missing
557+
#[error("Account in lookuptable is missing")]
558+
MissingAddressInLookuptable, // 633
559+
560+
/// Account is protected, it cannot be passed into a CPI as writable
561+
#[error("Account is protected, it cannot be passed into a CPI as writable")]
562+
ProtectedAccount, // 634
563+
564+
/// TransactionMessage is malformed
565+
#[error("TransactionMessage is malformed")]
566+
InvalidTransactionMessage, // 635
567+
568+
/// Transaction buffer already created
569+
#[error("Transaction buffer already created")]
570+
TransactionBufferAlreadyExists, // 636
571+
572+
/// Versioned Transaction already created
573+
#[error("Versioned Transaction already created")]
574+
VersionedTransactionAlreadyExists, // 637
575+
576+
/// Transaction buffer unauthorized extension
577+
#[error("Transaction buffer unauthorized extension")]
578+
TransactionBufferUnauthorizedExtension, // 638
579+
580+
/// Versioned Transaction already removed
581+
#[error("Versioned Transaction already removed")]
582+
VersionedTransactionAlreadyRemoved, // 639
583+
584+
/// Final buffer exceeded 10128 bytes
585+
#[error("Final buffer exceeded 10128 bytes")]
586+
FinalBufferSizeExceeded, // 640
587+
588+
/// Final message buffer hash doesnt match the expected hash
589+
#[error("Final message buffer hash doesnt match the expected hash")]
590+
FinalBufferHashMismatch, // 641
591+
592+
/// Final buffer size mismatch
593+
#[error("Final buffer size mismatch")]
594+
FinalBufferSizeMismatch, // 642
595+
596+
/// Invalid number of accounts in the address look up table account
597+
#[error("Invalid number of accounts in the address look up table account")]
598+
InvalidNumberOfAccounts, // 643
599+
600+
/// Transaction buffer does not exist
601+
#[error("Transaction buffer does not exist")]
602+
TransactionBufferDoesNotExist, // 644
603+
527604
}
528605

529606
impl PrintProgramError for GovernanceError {

0 commit comments

Comments
 (0)