diff --git a/docs/design/mimd-0024-fraud-proofs.md b/docs/design/mimd-0024-fraud-proofs.md
index 6e84e459..ea2f6c97 100644
--- a/docs/design/mimd-0024-fraud-proofs.md
+++ b/docs/design/mimd-0024-fraud-proofs.md
@@ -163,7 +163,7 @@ state_commitment_hash = H(
delegation_cluster,
operator_identity,
account_pubkey,
- commit_id,
+ commit_seq,
delegation_record,
da_pointer_hash,
account_state_hash,
@@ -177,7 +177,7 @@ challenge_hash = H(
operator_identity,
challenger_identity,
account_pubkey,
- commit_id,
+ commit_seq,
challenger_lamports,
challenger_owner,
challenger_data_hash,
@@ -198,9 +198,9 @@ Seed strings are placeholders until frozen.
| `OperatorBond` | `["operator-bond", delegation_cluster]` | Cluster-scoped operator stake for the challenge flow that survives validator rotation. |
| `VerifierBond` | `["verifier-bond", delegation_cluster, verifier]` | Verifier stake isolated to one cluster. |
| `VerifierRegistry` | `["verifier-registry", delegation_cluster]` | Verifiers selectable for one challenge-enabled cluster. |
-| `PendingCommitment` | `["pending-commitment", account, commit_id]` | Main commitment state machine. |
-| `StateBuffer` | `["state-buffer", account, commit_id, authority]` | Chunked state payload opened by an operator or challenger. The payload may be full `Account::data` bytes or an encoded diff. |
-| `Challenge` | `["challenge", account, commit_id, challenger]` | One challenge against one pending commitment. |
+| `PendingCommitment` | `["pending-commitment", account, commit_seq]` | Main commitment state machine. |
+| `StateBuffer` | `["state-buffer", account, commit_seq, authority]` | Chunked state payload opened by an operator or challenger. The payload may be full `Account::data` bytes or an encoded diff. |
+| `Challenge` | `["challenge", account, commit_seq, challenger]` | One challenge against one pending commitment. |
| `PayoutTimelock` | `["payout-timelock", challenge]` | Delayed payout for correct challenger. |
### Essential Fields
@@ -376,11 +376,11 @@ pub enum ResolvedStateSource {
ChallengerReveal,
}
-/// PDA: `["pending-commitment", account, commit_id]`
+/// PDA: `["pending-commitment", account, commit_seq]`
/// Created by: `ProposeCommitment`.
/// Closed by: `CloseTerminalAccounts` after finalize, cancel, or expiry.
///
-/// One account per delegated account and commit id.
+/// One account per delegated account and commit sequence number.
pub struct PendingCommitment {
/// Current state-machine state for this commitment.
pub status: PendingCommitmentStatus,
@@ -392,8 +392,8 @@ pub struct PendingCommitment {
pub operator_bond: Pubkey,
/// Delegated account whose base-layer state will be finalized.
pub account_pubkey: Pubkey,
- /// Validator-chosen nonce for this account commitment.
- pub commit_id: u64,
+ /// Monotonically increasing sequence number for this account's commitments.
+ pub commit_seq: u32,
/// Delegation metadata tying this account to the ER context.
pub delegation_record: Pubkey,
/// Hash of replay/data-availability pointer bytes.
@@ -406,8 +406,8 @@ pub struct PendingCommitment {
pub lamports: u64,
/// Owner committed by the operator.
pub owner: Pubkey,
- /// Hash binding cluster, validator, account, commit id, delegation, DA,
- /// and state.
+ /// Hash binding cluster, validator, account, commit sequence number,
+ /// delegation, DA, and state.
pub state_commitment_hash: [u8; 32],
/// Registry account used when this commitment was posted.
pub verifier_registry: Pubkey,
@@ -454,7 +454,7 @@ pub struct SelectedVerifier {
// Review: `challenge_window_id` should be kept only if window extensions or
// retries need an explicit round id.
-/// PDA: `["state-buffer", account, commit_id, authority]`
+/// PDA: `["state-buffer", account, commit_seq, authority]`
/// Created by: first `WriteStateBuffer`.
/// Frozen by: final `WriteStateBuffer` chunk.
/// Closed by: `CloseTerminalAccounts`.
@@ -470,7 +470,7 @@ pub struct StateBuffer {
pub account_pubkey: Pubkey,
/// Commitment this buffer belongs to.
- pub commit_id: u64,
+ pub commit_seq: u32,
/// Hash of the uploaded payload. Zero until finalized.
pub data_hash: [u8; 32],
@@ -509,7 +509,7 @@ pub enum ChallengeOutcome {
ChallengerCorrectOperatorSlashed,
}
-/// PDA: `["challenge", account, commit_id, challenger]`
+/// PDA: `["challenge", account, commit_seq, challenger]`
/// Created by: `RaiseChallenge`.
/// Closed by: `CloseTerminalAccounts` after a terminal challenge outcome.
///
@@ -596,8 +596,8 @@ Commitment, approval, challenge, resolution, and finalization instructions.
| Instruction | Expected invoker | Description |
| --- | --- | --- |
-| `WriteStateBuffer`
- ix-data:
commit_id, total_len, offset, chunk - accounts: payer signer, authority signer, StateBuffer, delegated account, system program
| Authority for a known state-buffer flow | System-level instruction. Creates, grows, writes, and finalizes a DLP-owned `StateBuffer` PDA using the fixed `["state-buffer", account, commit_id, authority]` seed pattern. The instruction remains cluster-neutral; consuming instructions validate the payload, authority, and cluster relationship. |
-| `ProposeCommitment`- ix-data:
commit_id, lamports, owner, da_pointer_hash, er_slot - accounts: current validator signer, OperatorBond, PendingCommitment, finalized operator StateBuffer, delegated account, DelegationRecord, DelegationMetadata, DelegationCluster, VerifierRegistry, system program
| Current validator | Requires `Challenge` mode, verifies the delegation's cluster and current validator, consumes only cluster-scoped bond and registry accounts, selects verifiers, and starts the challenge window. `DelegationRecord` and `DelegationMetadata` are temporary v1-layout dependencies until their v2 replacement exists. |
+| `WriteStateBuffer`- ix-data:
commit_seq, total_len, offset, chunk - accounts: payer signer, authority signer, StateBuffer, delegated account, system program
| Authority for a known state-buffer flow | System-level instruction. Creates, grows, writes, and finalizes a DLP-owned `StateBuffer` PDA using the fixed `["state-buffer", account, commit_seq, authority]` seed pattern. The instruction remains cluster-neutral; consuming instructions validate the payload, authority, and cluster relationship. |
+| `ProposeCommitment`- ix-data:
commit_seq, lamports, owner, da_pointer_hash, er_slot - accounts: current validator signer, OperatorBond, PendingCommitment, finalized operator StateBuffer, delegated account, DelegationRecord, DelegationMetadata, DelegationCluster, VerifierRegistry, system program
| Current validator | Requires `Challenge` mode, verifies the delegation's cluster and current validator, consumes only cluster-scoped bond and registry accounts, selects verifiers, and starts the challenge window. `DelegationRecord` and `DelegationMetadata` are temporary v1-layout dependencies until their v2 replacement exists. |
| `ApproveCommitment`- ix-data:
empty - accounts: verifier signer, VerifierBond, PendingCommitment
| Selected verifier | Records approval from the selected verifier. v2 MVP requires exactly one selected verifier, so no verifier index is needed. Duplicate approvals do not increase the count. |
| `RaiseChallenge`- ix-data:
state_commitment_hash, challenge_hash, stake_lamports - accounts: challenger signer, Challenge, PendingCommitment, DelegationCluster, system program
| Challenger | Requires the cluster stored by the pending commitment, locks challenger stake, stores the salted `challenge_hash`, and blocks normal finalization until reveal, timeout, or resolution. It does not consume challenger state bytes. |
| `ChallengerReveal`- ix-data:
lamports, owner, data_hash, salt - accounts: challenger signer, Challenge, PendingCommitment, finalized operator StateBuffer, finalized challenger StateBuffer, DelegationCluster, protocol fee vault
| Challenger | Opens the challenged state and salt, validates both state buffers and the stored `challenge_hash`, penalizes invalid or matching reveals, or moves mismatches to resolver decision. |
@@ -653,10 +653,10 @@ create and write accounts in the `StateBuffer` namespace, using the fixed seed
pattern:
```text
-["state-buffer", account, commit_id, authority]
+["state-buffer", account, commit_seq, authority]
```
-The header must bind the same `authority`, `account_pubkey`, and `commit_id`.
+The header must bind the same `authority`, `account_pubkey`, and `commit_seq`.
The buffer is inert until a consuming instruction validates the authority role:
- `ProposeCommitment` accepts a finalized buffer whose authority is the operator;
@@ -666,7 +666,7 @@ The buffer is inert until a consuming instruction validates the authority role:
needs buffered transport, and validates authority against the challenger.
If future protocol flows need multiple buffer purposes for the same
-`account + commit_id + authority`, add an explicit `buffer_kind` or purpose seed
+`account + commit_seq + authority`, add an explicit `buffer_kind` or purpose seed
and matching header field. Reusing the same address space for unrelated opened
state can create collisions or confused-consumer bugs.
@@ -676,7 +676,7 @@ duplicate retries remain valid.
Consuming instructions must check:
-- buffer PDA seeds match `account_pubkey`, `commit_id`, and `authority`;
+- buffer PDA seeds match `account_pubkey`, `commit_seq`, and `authority`;
- buffer is finalized;
- buffer commitment matches the `PendingCommitment`;
- authority matches the operator for `ProposeCommitment` and happy-path
@@ -692,7 +692,7 @@ are too slow.
```rust
pub struct WriteStateBufferArgs<'a> {
- pub commit_id: u64,
+ pub commit_seq: u32,
pub total_len: u32,
/// Must equal StateBuffer.payload.len(), unless retrying an exact old chunk.
pub offset: u32,
@@ -700,7 +700,7 @@ pub struct WriteStateBufferArgs<'a> {
}
pub struct ProposeCommitmentArgs {
- pub commit_id: u64,
+ pub commit_seq: u32,
pub lamports: u64,
pub owner: Pubkey,
pub da_pointer_hash: [u8; 32],
@@ -743,7 +743,7 @@ pub struct ResolveDisputeArgs {
instructions retain their validator-key authorization model.
- `WriteStateBuffer` must run before `ProposeCommitment` for the operator state.
`ProposeCommitment` rejects if the operator buffer is missing, unfinished, or
- belongs to another account, commit id, or current validator.
+ belongs to another account, commit sequence number, or current validator.
- `ProposeCommitment` reads `data_hash` from the finalized operator buffer,
verifies that the delegation, operator bond, and verifier registry belong to
the same cluster, computes `account_state_hash` and
diff --git a/interface/src/args/delegate.rs b/interface/src/args/delegate.rs
new file mode 100644
index 00000000..bda44a87
--- /dev/null
+++ b/interface/src/args/delegate.rs
@@ -0,0 +1,48 @@
+use wheels::variable_offset_layout;
+
+/// One owner-program seed used to derive the delegated account.
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[variable_offset_layout(buffer_offset = unknown)]
+pub struct DelegationSeed {
+ #[flexible = 1]
+ pub value: Vec,
+}
+
+impl<'a> DelegationSeedView<'a> {
+ /// Returns the seed without its one-byte variable-layout length prefix.
+ pub fn as_slice(&self) -> &'a [u8] {
+ &self.bytes()[1..]
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[variable_offset_layout(buffer_offset = 1)]
+pub struct DelegateArgs {
+ /// Bump for the owner-program delegate buffer PDA.
+ /// Set by the instruction builder.
+ pub delegate_buffer_bump: u8,
+
+ /// Bump for the DLP-owned DelegationState PDA.
+ /// Set by the instruction builder.
+ pub delegation_state_bump: u8,
+
+ /// Bump used with `seeds` to derive an off-curve delegated account.
+ /// Must be zero for an on-curve delegated account.
+ pub delegated_account_bump: u8,
+
+ /// Owner-program seeds used to derive an off-curve delegated account.
+ #[flexible = 1]
+ #[element_size = variable]
+ pub seeds: Vec,
+}
+
+impl DelegateArgs {
+ pub fn new(delegated_account_bump: u8, seeds: Vec) -> Self {
+ Self {
+ delegate_buffer_bump: 0,
+ delegation_state_bump: 0,
+ delegated_account_bump,
+ seeds,
+ }
+ }
+}
diff --git a/interface/src/args/mod.rs b/interface/src/args/mod.rs
index 68103ced..127da0fc 100644
--- a/interface/src/args/mod.rs
+++ b/interface/src/args/mod.rs
@@ -2,6 +2,7 @@
// instruction tag, so v2 instruction args use `buffer_offset = 1`.
mod challenger_reveal;
+mod delegate;
mod init_delegation_cluster;
mod propose_commitment;
mod raise_challenge;
@@ -13,6 +14,7 @@ mod update_verifier_registry;
mod write_state_buffer;
pub use challenger_reveal::*;
+pub use delegate::*;
pub use init_delegation_cluster::*;
pub use propose_commitment::*;
pub use raise_challenge::*;
diff --git a/interface/src/args/propose_commitment.rs b/interface/src/args/propose_commitment.rs
index ba6face9..7c7b5f40 100644
--- a/interface/src/args/propose_commitment.rs
+++ b/interface/src/args/propose_commitment.rs
@@ -5,7 +5,7 @@ use crate::compat::Pubkey;
#[derive(Clone, Debug, PartialEq, Eq)]
#[variable_offset_layout(buffer_offset = 1)]
pub struct ProposeCommitmentArgs {
- pub commit_id: u64,
+ pub commit_seq: u32,
pub lamports: u64,
diff --git a/interface/src/args/write_state_buffer.rs b/interface/src/args/write_state_buffer.rs
index ce6781bc..4fed230e 100644
--- a/interface/src/args/write_state_buffer.rs
+++ b/interface/src/args/write_state_buffer.rs
@@ -3,7 +3,7 @@ use wheels::variable_offset_layout;
#[derive(Clone, Debug, PartialEq, Eq)]
#[variable_offset_layout(buffer_offset = 1)]
pub struct WriteStateBufferArgs {
- pub commit_id: u64,
+ pub commit_seq: u32,
pub total_len: u32,
diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs
index 33241858..e0a65cb9 100644
--- a/interface/src/instruction.rs
+++ b/interface/src/instruction.rs
@@ -33,6 +33,8 @@ pub enum DlpV2Instruction {
ChallengerReveal = 110,
/// Applies resolver decision for a v2 challenge.
ResolveDispute = 111,
+ /// Delegates an account to one delegation cluster.
+ Delegate = 112,
}
impl DlpV2Instruction {
diff --git a/interface/src/instruction_builder/approve_commitment.rs b/interface/src/instruction_builder/approve_commitment.rs
index 400d0478..b7b9efa1 100644
--- a/interface/src/instruction_builder/approve_commitment.rs
+++ b/interface/src/instruction_builder/approve_commitment.rs
@@ -14,7 +14,7 @@ pub fn approve_commitment(
verifier: Pubkey,
delegation_cluster: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
) -> Instruction {
Instruction {
program_id: crate::id().modernize(),
@@ -29,7 +29,7 @@ pub fn approve_commitment(
false,
),
AccountMeta::new(
- pending_commitment_pda(&account.compatize(), commit_id)
+ pending_commitment_pda(&account.compatize(), commit_seq)
.modernize(),
false,
),
diff --git a/interface/src/instruction_builder/challenger_reveal.rs b/interface/src/instruction_builder/challenger_reveal.rs
index bf86d698..767c5397 100644
--- a/interface/src/instruction_builder/challenger_reveal.rs
+++ b/interface/src/instruction_builder/challenger_reveal.rs
@@ -17,7 +17,7 @@ pub fn challenger_reveal(
operator: Pubkey,
delegation_cluster: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
args: ChallengerRevealArgs,
) -> Instruction {
Instruction {
@@ -27,21 +27,21 @@ pub fn challenger_reveal(
AccountMeta::new(
challenge_pda(
&account.compatize(),
- commit_id,
+ commit_seq,
&challenger.compatize(),
)
.modernize(),
false,
),
AccountMeta::new(
- pending_commitment_pda(&account.compatize(), commit_id)
+ pending_commitment_pda(&account.compatize(), commit_seq)
.modernize(),
false,
),
AccountMeta::new_readonly(
state_buffer_pda(
&account.compatize(),
- commit_id,
+ commit_seq,
&operator.compatize(),
)
.modernize(),
@@ -50,7 +50,7 @@ pub fn challenger_reveal(
AccountMeta::new_readonly(
state_buffer_pda(
&account.compatize(),
- commit_id,
+ commit_seq,
&challenger.compatize(),
)
.modernize(),
diff --git a/interface/src/instruction_builder/delegate.rs b/interface/src/instruction_builder/delegate.rs
new file mode 100644
index 00000000..9bae73fd
--- /dev/null
+++ b/interface/src/instruction_builder/delegate.rs
@@ -0,0 +1,52 @@
+use solana_program::{
+ instruction::{AccountMeta, Instruction},
+ pubkey::Pubkey,
+};
+use solana_sdk_ids::system_program;
+use wheels::{layout::Encodable, DataLayoutError};
+
+use crate::{
+ compat::{Compatize, Modernize},
+ legacy::pda::DELEGATE_BUFFER_TAG,
+ pda::{delegation_state_pda, DELEGATION_STATE_SEED},
+ DelegateArgs, DlpV2Instruction,
+};
+
+/// Builds the shared instruction that delegates an account to one cluster.
+pub fn delegate(
+ payer: Pubkey,
+ delegated_account: Pubkey,
+ original_owner: Pubkey,
+ delegation_cluster: Pubkey,
+ mut args: DelegateArgs,
+) -> Result {
+ let (delegate_buffer, delegate_buffer_bump) = Pubkey::find_program_address(
+ &[DELEGATE_BUFFER_TAG, delegated_account.as_ref()],
+ &original_owner,
+ );
+ let (_, delegation_state_bump) = Pubkey::find_program_address(
+ &[DELEGATION_STATE_SEED, delegated_account.as_ref()],
+ &crate::id().modernize(),
+ );
+ args.delegate_buffer_bump = delegate_buffer_bump;
+ args.delegation_state_bump = delegation_state_bump;
+ let data = [DlpV2Instruction::Delegate.to_vec(), args.encode()?].concat();
+
+ Ok(Instruction {
+ program_id: crate::id().modernize(),
+ accounts: vec![
+ AccountMeta::new(payer, true),
+ AccountMeta::new(delegated_account, true),
+ AccountMeta::new_readonly(original_owner, false),
+ AccountMeta::new(delegate_buffer, false),
+ AccountMeta::new(
+ delegation_state_pda(&delegated_account.compatize())
+ .modernize(),
+ false,
+ ),
+ AccountMeta::new_readonly(delegation_cluster, false),
+ AccountMeta::new_readonly(system_program::id(), false),
+ ],
+ data,
+ })
+}
diff --git a/interface/src/instruction_builder/finalize_commitment.rs b/interface/src/instruction_builder/finalize_commitment.rs
index 4d3d73c4..506d70b2 100644
--- a/interface/src/instruction_builder/finalize_commitment.rs
+++ b/interface/src/instruction_builder/finalize_commitment.rs
@@ -19,13 +19,13 @@ pub fn finalize_commitment(
operator: Pubkey,
delegation_cluster: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
) -> Instruction {
finalize_commitment_with_state_authority(
operator,
delegation_cluster,
account,
- commit_id,
+ commit_seq,
None,
)
}
@@ -35,17 +35,20 @@ pub fn finalize_challenger_commitment(
challenger: Pubkey,
delegation_cluster: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
) -> Instruction {
- let challenge =
- challenge_pda(&account.compatize(), commit_id, &challenger.compatize())
- .modernize();
+ let challenge = challenge_pda(
+ &account.compatize(),
+ commit_seq,
+ &challenger.compatize(),
+ )
+ .modernize();
finalize_commitment_with_state_authority(
challenger,
delegation_cluster,
account,
- commit_id,
+ commit_seq,
Some(challenge),
)
}
@@ -54,13 +57,14 @@ fn finalize_commitment_with_state_authority(
state_authority: Pubkey,
delegation_cluster: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
challenge: Option,
) -> Instruction {
let mut accounts = vec![
AccountMeta::new(state_authority, true),
AccountMeta::new(
- pending_commitment_pda(&account.compatize(), commit_id).modernize(),
+ pending_commitment_pda(&account.compatize(), commit_seq)
+ .modernize(),
false,
),
AccountMeta::new(account, false),
@@ -79,7 +83,7 @@ fn finalize_commitment_with_state_authority(
AccountMeta::new_readonly(
state_buffer_pda(
&account.compatize(),
- commit_id,
+ commit_seq,
&state_authority.compatize(),
)
.modernize(),
diff --git a/interface/src/instruction_builder/mod.rs b/interface/src/instruction_builder/mod.rs
index 5479da8b..2a4b5eb0 100644
--- a/interface/src/instruction_builder/mod.rs
+++ b/interface/src/instruction_builder/mod.rs
@@ -1,5 +1,6 @@
mod approve_commitment;
mod challenger_reveal;
+mod delegate;
mod finalize_commitment;
mod init_delegation_cluster;
mod propose_commitment;
@@ -13,6 +14,7 @@ mod write_state_buffer;
pub use approve_commitment::*;
pub use challenger_reveal::*;
+pub use delegate::*;
pub use finalize_commitment::*;
pub use init_delegation_cluster::*;
pub use propose_commitment::*;
diff --git a/interface/src/instruction_builder/propose_commitment.rs b/interface/src/instruction_builder/propose_commitment.rs
index 046559bd..d4bd7b94 100644
--- a/interface/src/instruction_builder/propose_commitment.rs
+++ b/interface/src/instruction_builder/propose_commitment.rs
@@ -34,14 +34,14 @@ pub fn propose_commitment(
false,
),
AccountMeta::new(
- pending_commitment_pda(&account.compatize(), args.commit_id)
+ pending_commitment_pda(&account.compatize(), args.commit_seq)
.modernize(),
false,
),
AccountMeta::new_readonly(
state_buffer_pda(
&account.compatize(),
- args.commit_id,
+ args.commit_seq,
¤t_validator.compatize(),
)
.modernize(),
diff --git a/interface/src/instruction_builder/raise_challenge.rs b/interface/src/instruction_builder/raise_challenge.rs
index c2f4c844..04d6e12e 100644
--- a/interface/src/instruction_builder/raise_challenge.rs
+++ b/interface/src/instruction_builder/raise_challenge.rs
@@ -16,7 +16,7 @@ pub fn raise_challenge(
challenger: Pubkey,
delegation_cluster: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
args: RaiseChallengeArgs,
) -> Instruction {
Instruction {
@@ -26,14 +26,14 @@ pub fn raise_challenge(
AccountMeta::new(
challenge_pda(
&account.compatize(),
- commit_id,
+ commit_seq,
&challenger.compatize(),
)
.modernize(),
false,
),
AccountMeta::new(
- pending_commitment_pda(&account.compatize(), commit_id)
+ pending_commitment_pda(&account.compatize(), commit_seq)
.modernize(),
false,
),
diff --git a/interface/src/instruction_builder/resolve_dispute.rs b/interface/src/instruction_builder/resolve_dispute.rs
index da155e75..8d65cc52 100644
--- a/interface/src/instruction_builder/resolve_dispute.rs
+++ b/interface/src/instruction_builder/resolve_dispute.rs
@@ -17,7 +17,7 @@ pub fn resolve_dispute(
delegation_cluster: Pubkey,
challenger: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
args: ResolveDisputeArgs,
) -> Instruction {
Instruction {
@@ -27,14 +27,14 @@ pub fn resolve_dispute(
AccountMeta::new(
challenge_pda(
&account.compatize(),
- commit_id,
+ commit_seq,
&challenger.compatize(),
)
.modernize(),
false,
),
AccountMeta::new(
- pending_commitment_pda(&account.compatize(), commit_id)
+ pending_commitment_pda(&account.compatize(), commit_seq)
.modernize(),
false,
),
diff --git a/interface/src/instruction_builder/write_state_buffer.rs b/interface/src/instruction_builder/write_state_buffer.rs
index 903b3f94..4c5417be 100644
--- a/interface/src/instruction_builder/write_state_buffer.rs
+++ b/interface/src/instruction_builder/write_state_buffer.rs
@@ -26,7 +26,7 @@ pub fn write_state_buffer(
AccountMeta::new(
state_buffer_pda(
&account.compatize(),
- args.commit_id,
+ args.commit_seq,
&authority.compatize(),
)
.modernize(),
diff --git a/interface/src/pda.rs b/interface/src/pda.rs
index c728409b..0bce2400 100644
--- a/interface/src/pda.rs
+++ b/interface/src/pda.rs
@@ -1,6 +1,7 @@
use crate::compat::Pubkey;
pub const DELEGATION_CLUSTER_SEED: &[u8] = b"delegation-cluster";
+pub const DELEGATION_STATE_SEED: &[u8] = b"delegation-state";
pub const OPERATOR_BOND_SEED: &[u8] = b"operator-bond";
pub const VERIFIER_BOND_SEED: &[u8] = b"verifier-bond";
pub const VERIFIER_REGISTRY_SEED: &[u8] = b"verifier-registry";
@@ -18,6 +19,14 @@ pub fn delegation_cluster_pda(cluster_id: &Pubkey) -> Pubkey {
.0
}
+pub fn delegation_state_pda(delegated_account: &Pubkey) -> Pubkey {
+ Pubkey::find_program_address(
+ &[DELEGATION_STATE_SEED, delegated_account.as_ref()],
+ &crate::id(),
+ )
+ .0
+}
+
pub fn verifier_registry_pda(delegation_cluster: &Pubkey) -> Pubkey {
Pubkey::find_program_address(
&[VERIFIER_REGISTRY_SEED, delegation_cluster.as_ref()],
@@ -51,14 +60,14 @@ pub fn verifier_bond_pda(
pub fn state_buffer_pda(
account: &Pubkey,
- commit_id: u64,
+ commit_seq: u32,
authority: &Pubkey,
) -> Pubkey {
Pubkey::find_program_address(
&[
STATE_BUFFER_SEED,
account.as_ref(),
- &commit_id.to_le_bytes(),
+ &commit_seq.to_le_bytes(),
authority.as_ref(),
],
&crate::id(),
@@ -66,12 +75,12 @@ pub fn state_buffer_pda(
.0
}
-pub fn pending_commitment_pda(account: &Pubkey, commit_id: u64) -> Pubkey {
+pub fn pending_commitment_pda(account: &Pubkey, commit_seq: u32) -> Pubkey {
Pubkey::find_program_address(
&[
PENDING_COMMITMENT_SEED,
account.as_ref(),
- &commit_id.to_le_bytes(),
+ &commit_seq.to_le_bytes(),
],
&crate::id(),
)
@@ -80,14 +89,14 @@ pub fn pending_commitment_pda(account: &Pubkey, commit_id: u64) -> Pubkey {
pub fn challenge_pda(
account: &Pubkey,
- commit_id: u64,
+ commit_seq: u32,
challenger: &Pubkey,
) -> Pubkey {
Pubkey::find_program_address(
&[
CHALLENGE_SEED,
account.as_ref(),
- &commit_id.to_le_bytes(),
+ &commit_seq.to_le_bytes(),
challenger.as_ref(),
],
&crate::id(),
diff --git a/interface/src/state/challenge.rs b/interface/src/state/challenge.rs
index eb38d797..b44f8df4 100644
--- a/interface/src/state/challenge.rs
+++ b/interface/src/state/challenge.rs
@@ -12,7 +12,7 @@ pub const CHALLENGE_OUTCOME_MATCHING_STATE_CHALLENGER_PENALIZED: u8 = 2;
pub const CHALLENGE_OUTCOME_OPERATOR_CORRECT_CHALLENGER_SLASHED: u8 = 3;
pub const CHALLENGE_OUTCOME_CHALLENGER_CORRECT_OPERATOR_SLASHED: u8 = 4;
-/// PDA: `["challenge", account, commit_id, challenger]`.
+/// PDA: `["challenge", account, commit_seq, challenger]`.
/// Created by `RaiseChallenge`.
/// Closed by `CloseTerminalAccounts` after terminal challenge outcome.
#[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/interface/src/state/delegation_state.rs b/interface/src/state/delegation_state.rs
new file mode 100644
index 00000000..0dcb0711
--- /dev/null
+++ b/interface/src/state/delegation_state.rs
@@ -0,0 +1,93 @@
+use wheels::{
+ fixed_offset_layout, layout::VariableLayoutSlice, DataLayoutError,
+};
+
+use crate::{compat::Pubkey, error::DlpError, DelegationSeed};
+
+/// PDA: `["delegation-state", delegated_account]`.
+/// Created by `Delegate`; closed when the account is undelegated.
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[fixed_offset_layout(buffer_offset = 0)]
+pub struct DelegationState {
+ /// Account type marker.
+ pub discriminator: [u8; 8],
+
+ /// Canonical PDA bump for this account.
+ pub bump: u8,
+
+ /// Account controlled by this delegation state.
+ pub delegated_account: Pubkey,
+
+ /// Stable cluster authority for this delegation.
+ pub delegation_cluster: Pubkey,
+
+ /// Program that owned the account before delegation.
+ pub original_owner: Pubkey,
+
+ /// Account that paid to create this delegation state.
+ pub rent_payer: Pubkey,
+
+ /// Slot in which this delegation was created.
+ pub delegation_slot: u64,
+
+ /// Account lamports at delegation or after the latest finalization.
+ pub lamports: u64,
+
+ /// Latest finalized commit sequence number applied to the delegated account.
+ pub last_commit_seq: u32,
+
+ /// Who requested undelegation, stored as `UndelegationRequester::value()`.
+ pub undelegation_requester: u8,
+
+ /// Bump used with the stored seeds for an off-curve delegated account.
+ pub delegated_account_bump: u8,
+
+ /// Number of owner-program seeds encoded in `encoded_seeds`.
+ pub seed_count: u8,
+
+ /// Self-delimiting `DelegationSeed` values used to derive the account.
+ #[extendable = 2]
+ pub encoded_seeds: Vec,
+}
+
+impl DelegationState {
+ pub const DISCRIMINATOR: [u8; 8] = *b"v2delst0";
+ pub const MAX_SEEDS: usize = 8;
+ pub const MAX_SEED_LEN: usize = 32;
+ pub const ENCODED_SEEDS_LEN_HEADER_LEN: usize = 2;
+
+ pub fn data_len_from_encoded_seeds_len(
+ encoded_seeds_len: usize,
+ ) -> Result {
+ Self::MIN_DATA_LEN
+ .checked_add(Self::ENCODED_SEEDS_LEN_HEADER_LEN)
+ .and_then(|len| len.checked_add(encoded_seeds_len))
+ .ok_or(DlpError::Overflow)
+ }
+}
+
+impl<'a> DelegationStateView<'a> {
+ pub fn seeds(
+ &self,
+ ) -> Result, DataLayoutError> {
+ VariableLayoutSlice::new(
+ self.encoded_seeds().as_slice(),
+ self.seed_count() as usize,
+ )
+ }
+}
+
+/// Identifies who requested that a delegated account be undelegated.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum UndelegationRequester {
+ None = 0,
+ Validator = 1,
+ OwnerProgram = 2,
+}
+
+impl UndelegationRequester {
+ pub const fn value(self) -> u8 {
+ self as u8
+ }
+}
diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs
index 9dfc0921..652e2755 100644
--- a/interface/src/state/mod.rs
+++ b/interface/src/state/mod.rs
@@ -1,5 +1,6 @@
mod challenge;
mod delegation_cluster;
+mod delegation_state;
mod operator_bond;
mod pending_commitment;
mod state_buffer;
@@ -8,6 +9,7 @@ mod verifier_registry;
pub use challenge::*;
pub use delegation_cluster::*;
+pub use delegation_state::*;
pub use operator_bond::*;
pub use pending_commitment::*;
pub use state_buffer::*;
diff --git a/interface/src/state/pending_commitment.rs b/interface/src/state/pending_commitment.rs
index d423e0c8..4dc95937 100644
--- a/interface/src/state/pending_commitment.rs
+++ b/interface/src/state/pending_commitment.rs
@@ -15,11 +15,11 @@ pub const PENDING_COMMITMENT_STATUS_CANCELLED: u8 = 9;
pub const RESOLVED_STATE_SOURCE_OPERATOR_COMMITMENT: u8 = 1;
pub const RESOLVED_STATE_SOURCE_CHALLENGER_REVEAL: u8 = 2;
-/// PDA: `["pending-commitment", account, commit_id]`.
+/// PDA: `["pending-commitment", account, commit_seq]`.
/// Created by `ProposeCommitment`.
/// Closed by `CloseTerminalAccounts` after finalize, cancel, or expiry.
///
-/// One account per delegated account and commit id.
+/// One account per delegated account and commit sequence number.
#[derive(Clone, Debug, PartialEq, Eq)]
#[fixed_offset_layout(buffer_offset = 0)]
pub struct PendingCommitment {
@@ -41,8 +41,8 @@ pub struct PendingCommitment {
/// Delegated account whose base-layer state will be finalized.
pub account_pubkey: Pubkey,
- /// Operator-chosen nonce for this account commitment.
- pub commit_id: u64,
+ /// Monotonically increasing sequence number for this account's commitments.
+ pub commit_seq: u32,
/// Delegation record tying this account to the ER context.
pub delegation_record: Pubkey,
@@ -62,7 +62,8 @@ pub struct PendingCommitment {
/// Owner committed by the operator.
pub owner: Pubkey,
- /// Hash binding operator, account, commit id, delegation, DA, and state.
+ /// Hash binding operator, account, commit sequence number, delegation, DA,
+ /// and state.
pub state_commitment_hash: [u8; 32],
/// Registry account used when this commitment was posted.
@@ -108,7 +109,7 @@ pub struct PendingCommitment {
pub er_slot: Option,
/// Aligns selected verifier elements after the Vec length prefix.
- pub _pad_before_selected_verifiers: [u8; 5],
+ pub _pad_before_selected_verifiers: [u8; 9],
/// Verifiers selected by round-robin for this commitment.
#[extendable = 2]
diff --git a/interface/src/state/state_buffer.rs b/interface/src/state/state_buffer.rs
index 6f97bb09..f375f9d8 100644
--- a/interface/src/state/state_buffer.rs
+++ b/interface/src/state/state_buffer.rs
@@ -2,7 +2,7 @@ use wheels::fixed_offset_layout;
use crate::{compat::Pubkey, error::DlpError};
-/// PDA: `["state-buffer", account, commit_id, authority]`.
+/// PDA: `["state-buffer", account, commit_seq, authority]`.
/// Created by `WriteStateBuffer`.
/// Closed by `CloseTerminalAccounts` after finalize, cancel, or expiry.
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -20,8 +20,8 @@ pub struct StateBuffer {
/// Delegated account whose payload is stored after this header.
pub account_pubkey: Pubkey,
- /// Flow-specific nonce that identifies this opened buffer.
- pub commit_id: u64,
+ /// Commit sequence number that identifies this opened buffer.
+ pub commit_seq: u32,
/// Hash of the finalized payload. Zero until finalized.
pub data_hash: [u8; 32],
diff --git a/program/src/processor/delegate.rs b/program/src/processor/delegate.rs
new file mode 100644
index 00000000..63323a70
--- /dev/null
+++ b/program/src/processor/delegate.rs
@@ -0,0 +1,232 @@
+use delegation_program_interface as dpi;
+use dpi::{
+ error::DlpError,
+ legacy::pda::DELEGATE_BUFFER_TAG,
+ pda::{DELEGATION_CLUSTER_SEED, DELEGATION_STATE_SEED},
+ DelegateArgs, DelegationCluster, DelegationState, UndelegationRequester,
+};
+use pinocchio::{
+ address::{address_eq, Address},
+ cpi::{Seed, Signer},
+ error::ProgramError,
+ sysvars::{clock::Clock, rent::Rent, Sysvar},
+ AccountView, ProgramResult,
+};
+use pinocchio_system::instructions as system;
+use wheels::{
+ layout::Decodable, require, require_eq, require_eq_keys, require_le,
+ require_n_accounts, require_owned_by, require_signer,
+};
+
+use crate::{
+ legacy::processor::{
+ fast::utils::pda::{create_pda, AccountSpace},
+ utils::curve::is_on_curve_fast,
+ },
+ requires::{require_uninitialized_account, StandardCtx},
+};
+
+/// Delegate an account to one delegation cluster.
+///
+/// Accounts:
+/// 0: `[signer, writable]` delegation-state rent payer
+/// 1: `[signer, writable]` delegated account, signed by its owner program
+/// 2: `[]` original owner program
+/// 3: `[writable]` owner-program delegate buffer PDA
+/// 4: `[writable]` DelegationState PDA
+/// 5: `[]` DelegationCluster PDA
+/// 6: `[]` system program, required by system CPI
+#[inline(never)]
+pub fn process_delegate(
+ accounts: &[AccountView],
+ data: &[u8],
+) -> ProgramResult {
+ let [
+ payer, // force multi-line
+ delegated_account,
+ original_owner,
+ delegate_buffer,
+ delegation_state,
+ delegation_cluster,
+ _system_program,
+ ] = require_n_accounts!(accounts, 7);
+
+ require_signer!(payer);
+ require_signer!(delegated_account);
+ require_owned_by!(delegated_account, &crate::fast::ID);
+
+ let args = DelegateArgs::decode(data)?;
+ validate_delegated_account(delegated_account, original_owner, &args)?;
+
+ let delegate_buffer_bump = [args.delegate_buffer_bump()];
+ dpi::require_pda!(
+ delegate_buffer,
+ &[
+ DELEGATE_BUFFER_TAG,
+ delegated_account.address().as_ref(),
+ &delegate_buffer_bump,
+ ],
+ original_owner.address(),
+ true
+ );
+
+ let delegation_state_bump = [args.delegation_state_bump()];
+ dpi::require_pda!(
+ delegation_state,
+ &[
+ DELEGATION_STATE_SEED,
+ delegated_account.address().as_ref(),
+ &delegation_state_bump,
+ ],
+ &crate::fast::ID,
+ true
+ );
+ require_uninitialized_account(
+ delegation_state,
+ true,
+ StandardCtx::new("delegation state"),
+ )?;
+
+ let delegation_cluster_data = delegation_cluster.try_borrow()?;
+ let delegation_cluster_state =
+ DelegationCluster::decode(delegation_cluster_data.as_ref())?;
+ let delegation_cluster_bump = [delegation_cluster_state.bump()];
+ dpi::require_initialized_pda!(
+ delegation_cluster,
+ &[
+ DELEGATION_CLUSTER_SEED,
+ delegation_cluster_state.cluster_id().as_ref(),
+ &delegation_cluster_bump,
+ ],
+ &crate::fast::ID,
+ false
+ );
+ require_eq!(
+ &delegation_cluster_state.discriminator(),
+ &DelegationCluster::DISCRIMINATOR,
+ ProgramError::InvalidAccountData
+ );
+ require!(
+ !delegation_cluster_state.paused(),
+ ProgramError::InvalidAccountData
+ );
+ drop(delegation_cluster_data);
+
+ let seeds = args.seeds();
+ let encoded_seeds = seeds.as_bytes();
+ let state_len =
+ DelegationState::data_len_from_encoded_seeds_len(encoded_seeds.len())?;
+ let delegated_account_lamports = delegated_account.lamports();
+
+ create_pda(
+ delegation_state,
+ &crate::fast::ID,
+ AccountSpace::CurrentRent(state_len),
+ &[Signer::from(&[
+ Seed::from(DELEGATION_STATE_SEED),
+ Seed::from(delegated_account.address().as_ref()),
+ Seed::from(&delegation_state_bump),
+ ])],
+ payer,
+ )?;
+
+ let mut state = DelegationState::decode_mut(delegation_state)?;
+ *state.discriminator_mut()? = DelegationState::DISCRIMINATOR;
+ *state.bump_mut()? = args.delegation_state_bump();
+ *state.delegated_account_mut()? = *delegated_account.address();
+ *state.delegation_cluster_mut()? = *delegation_cluster.address();
+ *state.original_owner_mut()? = *original_owner.address();
+ *state.rent_payer_mut()? = *payer.address();
+ state.delegation_slot_mut()?.set(Clock::get()?.slot)?;
+ state.lamports_mut()?.set(delegated_account_lamports)?;
+ state.last_commit_seq_mut()?.set(0)?;
+ *state.undelegation_requester_mut()? = UndelegationRequester::None.value();
+ *state.delegated_account_bump_mut()? = args.delegated_account_bump();
+ *state.seed_count_mut()? = seeds.len() as u8;
+ state
+ .encoded_seeds_mut()?
+ .extend_from_slice(encoded_seeds)?;
+
+ if !delegate_buffer.is_data_empty() {
+ require_eq!(
+ delegate_buffer.data_len(),
+ delegated_account.data_len(),
+ ProgramError::InvalidAccountData
+ );
+ delegated_account
+ .try_borrow_mut()?
+ .copy_from_slice(delegate_buffer.try_borrow()?.as_ref());
+ }
+
+ // Preserve the original zero-lamport state in DelegationState, then fund
+ // an empty delegated account enough to keep it alive on the base layer.
+ if delegated_account_lamports == 0 && delegated_account.is_data_empty() {
+ system::Transfer {
+ from: payer,
+ to: delegated_account,
+ lamports: Rent::get()?.try_minimum_balance(0)?,
+ }
+ .invoke()?;
+ }
+
+ Ok(())
+}
+
+fn validate_delegated_account(
+ delegated_account: &AccountView,
+ original_owner: &AccountView,
+ args: &dpi::DelegateArgsView<'_>,
+) -> ProgramResult {
+ let seeds = args.seeds();
+ require_le!(
+ seeds.len(),
+ DelegationState::MAX_SEEDS,
+ DlpError::TooManySeeds
+ );
+
+ if is_on_curve_fast(delegated_account.address()) {
+ require_eq_keys!(
+ original_owner.address(),
+ &pinocchio_system::ID,
+ ProgramError::IncorrectProgramId
+ );
+ require_eq!(seeds.len(), 0, ProgramError::InvalidInstructionData);
+ require_eq!(
+ args.delegated_account_bump(),
+ 0,
+ ProgramError::InvalidInstructionData
+ );
+ return Ok(());
+ }
+
+ require!(!seeds.is_empty(), ProgramError::InvalidInstructionData);
+
+ let mut pda_seeds: [&[u8]; DelegationState::MAX_SEEDS + 1] =
+ [&[]; DelegationState::MAX_SEEDS + 1];
+ for (index, seed) in seeds.iter().enumerate() {
+ require_le!(
+ seed.as_slice().len(),
+ DelegationState::MAX_SEED_LEN,
+ ProgramError::MaxSeedLengthExceeded
+ );
+ pda_seeds[index] = seed.as_slice();
+ }
+ let delegated_account_bump = [args.delegated_account_bump()];
+ pda_seeds[seeds.len()] = &delegated_account_bump;
+
+ let owner = if address_eq(original_owner.address(), &pinocchio_system::ID) {
+ &crate::fast::ID
+ } else {
+ original_owner.address()
+ };
+ let derived_account =
+ Address::create_program_address(&pda_seeds[..=seeds.len()], owner)
+ .map_err(|_| ProgramError::InvalidSeeds)?;
+ require_eq_keys!(
+ &derived_account,
+ delegated_account.address(),
+ ProgramError::InvalidSeeds
+ );
+
+ Ok(())
+}
diff --git a/program/src/processor/fraud_proofs/approve_commitment.rs b/program/src/processor/fraud_proofs/approve_commitment.rs
index bf83c46e..1c586a03 100644
--- a/program/src/processor/fraud_proofs/approve_commitment.rs
+++ b/program/src/processor/fraud_proofs/approve_commitment.rs
@@ -149,13 +149,13 @@ fn validate_pending_commitment(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending_commitment.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending_commitment.commit_seq().to_le_bytes();
require_initialized_pda(
pending_commitment_account,
&[
PENDING_COMMITMENT_SEED,
pending_commitment.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
],
&crate::fast::ID,
true,
diff --git a/program/src/processor/fraud_proofs/challenger_reveal.rs b/program/src/processor/fraud_proofs/challenger_reveal.rs
index b36627cd..67e26212 100644
--- a/program/src/processor/fraud_proofs/challenger_reveal.rs
+++ b/program/src/processor/fraud_proofs/challenger_reveal.rs
@@ -99,7 +99,7 @@ pub fn process_challenger_reveal(
operator_state_buffer,
pending.operator_identity(),
pending.account_pubkey(),
- pending.commit_id(),
+ pending.commit_seq(),
pending.data_hash(),
)?;
@@ -108,7 +108,7 @@ pub fn process_challenger_reveal(
challenger_state_buffer,
&challenger_identity,
pending.account_pubkey(),
- pending.commit_id(),
+ pending.commit_seq(),
args.data_hash(),
)?;
@@ -229,13 +229,13 @@ fn validate_pending_commitment(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending.commit_seq().to_le_bytes();
require_initialized_pda(
pending_commitment,
&[
PENDING_COMMITMENT_SEED,
pending.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
],
&crate::fast::ID,
true,
@@ -276,13 +276,13 @@ fn validate_challenge(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending.commit_seq().to_le_bytes();
require_initialized_pda(
challenge,
&[
CHALLENGE_SEED,
pending.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
challenger.address().as_ref(),
],
&crate::fast::ID,
@@ -328,16 +328,16 @@ fn validate_state_buffer(
state_buffer: &AccountView,
authority: &dpi::compat::Pubkey,
account_pubkey: &dpi::compat::Pubkey,
- commit_id: u64,
+ commit_seq: u32,
expected_data_hash: &[u8; 32],
) -> ProgramResult {
- let commit_id_bytes = commit_id.to_le_bytes();
+ let commit_seq_bytes = commit_seq.to_le_bytes();
require_initialized_pda(
state_buffer,
&[
STATE_BUFFER_SEED,
account_pubkey.as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
authority.as_ref(),
],
&crate::fast::ID,
@@ -358,8 +358,8 @@ fn validate_state_buffer(
ProgramError::InvalidAccountData
);
require_eq!(
- state.commit_id(),
- commit_id,
+ state.commit_seq(),
+ commit_seq,
ProgramError::InvalidInstructionData
);
require_eq!(
@@ -440,7 +440,7 @@ fn challenge_hash(
pending.operator_identity().as_ref(),
challenge.challenger_identity().as_ref(),
pending.account_pubkey().as_ref(),
- &pending.commit_id().to_le_bytes(),
+ &pending.commit_seq().to_le_bytes(),
&args.lamports().to_le_bytes(),
args.owner().as_ref(),
args.data_hash(),
diff --git a/program/src/processor/fraud_proofs/finalize_commitment.rs b/program/src/processor/fraud_proofs/finalize_commitment.rs
index 4f7a6f33..ca5c4d19 100644
--- a/program/src/processor/fraud_proofs/finalize_commitment.rs
+++ b/program/src/processor/fraud_proofs/finalize_commitment.rs
@@ -198,13 +198,13 @@ pub fn process_finalize_commitment(
true,
)?;
- let commit_id_bytes = pending.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending.commit_seq().to_le_bytes();
require_initialized_pda(
state_buffer,
&[
STATE_BUFFER_SEED,
delegated_account.address().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
state_authority.address().as_ref(),
],
&crate::fast::ID,
@@ -217,14 +217,14 @@ pub fn process_finalize_commitment(
delegation_cluster,
selected_state.owner,
)?;
- validate_delegation_metadata(delegation_metadata, pending.commit_id())?;
+ validate_delegation_metadata(delegation_metadata, pending.commit_seq())?;
let state_buffer_data = state_buffer.try_borrow()?;
let raw_state = validate_state_buffer(
state_buffer_data.as_ref(),
state_authority,
delegated_account,
- pending.commit_id(),
+ pending.commit_seq(),
selected_state.data_hash,
)?;
@@ -256,7 +256,7 @@ pub fn process_finalize_commitment(
{
let mut metadata =
DelegationMetadataFast::from_account(delegation_metadata)?;
- metadata.set_last_commit_id(pending.commit_id());
+ metadata.set_last_commit_id(u64::from(pending.commit_seq()));
}
drop(delegation_cluster_data);
@@ -276,13 +276,13 @@ fn validate_pending_commitment(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending.commit_seq().to_le_bytes();
require_initialized_pda(
pending_commitment,
&[
PENDING_COMMITMENT_SEED,
pending.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
],
&crate::fast::ID,
true,
@@ -395,14 +395,18 @@ fn validate_delegation_record(
fn validate_delegation_metadata(
delegation_metadata: &AccountView,
- commit_id: u64,
+ commit_seq: u32,
) -> ProgramResult {
let metadata = DelegationMetadataFast::from_account(delegation_metadata)?;
- let expected_commit_id = metadata
+ let expected_commit_seq = metadata
.last_commit_id()
.checked_add(1)
.ok_or(DlpError::Overflow)?;
- require_eq!(commit_id, expected_commit_id, DlpError::NonceOutOfOrder);
+ require_eq!(
+ u64::from(commit_seq),
+ expected_commit_seq,
+ DlpError::NonceOutOfOrder
+ );
match metadata.undelegation_requester()? {
UndelegationRequester::None => Ok(()),
@@ -419,7 +423,7 @@ fn validate_state_buffer<'a>(
data: &'a [u8],
state_authority: &AccountView,
delegated_account: &AccountView,
- commit_id: u64,
+ commit_seq: u32,
expected_data_hash: &[u8; 32],
) -> Result<&'a [u8], ProgramError> {
let state = StateBuffer::decode(data)?;
@@ -438,8 +442,8 @@ fn validate_state_buffer<'a>(
DlpError::InvalidDelegatedAccount
);
require_eq!(
- state.commit_id(),
- commit_id,
+ state.commit_seq(),
+ commit_seq,
ProgramError::InvalidInstructionData
);
require_eq!(
@@ -533,13 +537,13 @@ fn validate_challenge(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending.commit_seq().to_le_bytes();
require_initialized_pda(
challenge_account,
&[
CHALLENGE_SEED,
pending.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
challenge.challenger_identity().as_ref(),
],
&crate::fast::ID,
diff --git a/program/src/processor/fraud_proofs/propose_commitment.rs b/program/src/processor/fraud_proofs/propose_commitment.rs
index c977e743..7dc49c2a 100644
--- a/program/src/processor/fraud_proofs/propose_commitment.rs
+++ b/program/src/processor/fraud_proofs/propose_commitment.rs
@@ -102,13 +102,13 @@ pub fn process_propose_commitment(
false,
"operator bond",
)?;
- let commit_id_bytes = args.commit_id().to_le_bytes();
+ let commit_seq_bytes = args.commit_seq().to_le_bytes();
require_initialized_pda(
state_buffer,
&[
STATE_BUFFER_SEED,
delegated_account.address().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
current_validator.address().as_ref(),
],
&crate::fast::ID,
@@ -154,7 +154,7 @@ pub fn process_propose_commitment(
&state_buffer_state,
current_validator,
delegated_account,
- args.commit_id(),
+ args.commit_seq(),
)?;
drop(state_buffer_data);
@@ -179,7 +179,7 @@ pub fn process_propose_commitment(
let delegation_metadata =
DelegationMetadataRef::from_account(delegation_metadata)?;
require_eq!(
- args.commit_id(),
+ u64::from(args.commit_seq()),
delegation_metadata
.last_commit_id()
.checked_add(1)
@@ -238,7 +238,7 @@ pub fn process_propose_commitment(
delegation_cluster: delegation_cluster.address(),
operator_identity: current_validator.address(),
account_pubkey: delegated_account.address(),
- commit_id: args.commit_id(),
+ commit_seq: args.commit_seq(),
delegation_record: delegation_record.address(),
da_pointer_hash: args.da_pointer_hash(),
account_state_hash: &account_state_hash,
@@ -253,7 +253,7 @@ pub fn process_propose_commitment(
operator_identity: *current_validator.address(),
operator_bond: operator_bond.address().to_bytes().into(),
account_pubkey: delegated_account.address().to_bytes().into(),
- commit_id: args.commit_id(),
+ commit_seq: args.commit_seq(),
delegation_record: delegation_record.address().to_bytes().into(),
da_pointer_hash: *args.da_pointer_hash(),
account_state_hash,
@@ -279,7 +279,7 @@ pub fn process_propose_commitment(
active_challenge: None,
resolved_state_source: None,
er_slot: args.er_slot(),
- _pad_before_selected_verifiers: [0; 5],
+ _pad_before_selected_verifiers: [0; 9],
selected_verifiers,
};
@@ -290,7 +290,7 @@ pub fn process_propose_commitment(
&[
PENDING_COMMITMENT_SEED,
delegated_account.address().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
],
&crate::fast::ID,
true,
@@ -304,7 +304,7 @@ pub fn process_propose_commitment(
&[Signer::from(&[
Seed::from(PENDING_COMMITMENT_SEED),
Seed::from(delegated_account.address().as_ref()),
- Seed::from(&commit_id_bytes),
+ Seed::from(&commit_seq_bytes),
Seed::from(&[pending_commitment_bump]),
])],
current_validator,
@@ -373,7 +373,7 @@ fn validate_state_buffer(
state_buffer: &dpi::StateBufferView<'_>,
operator: &AccountView,
delegated_account: &AccountView,
- commit_id: u64,
+ commit_seq: u32,
) -> Result<[u8; 32], ProgramError> {
if state_buffer.discriminator() != StateBuffer::DISCRIMINATOR {
return Err(ProgramError::InvalidAccountData);
@@ -389,8 +389,8 @@ fn validate_state_buffer(
ProgramError::InvalidAccountData
);
require_eq!(
- state_buffer.commit_id(),
- commit_id,
+ state_buffer.commit_seq(),
+ commit_seq,
ProgramError::InvalidInstructionData
);
require_eq!(
@@ -468,7 +468,7 @@ struct StateCommitmentHashInput<'a> {
delegation_cluster: &'a Address,
operator_identity: &'a Address,
account_pubkey: &'a Address,
- commit_id: u64,
+ commit_seq: u32,
delegation_record: &'a Address,
da_pointer_hash: &'a [u8; 32],
account_state_hash: &'a [u8; 32],
@@ -482,7 +482,7 @@ fn state_commitment_hash(input: StateCommitmentHashInput<'_>) -> [u8; 32] {
input.delegation_cluster.as_ref(),
input.operator_identity.as_ref(),
input.account_pubkey.as_ref(),
- &input.commit_id.to_le_bytes(),
+ &input.commit_seq.to_le_bytes(),
input.delegation_record.as_ref(),
input.da_pointer_hash,
input.account_state_hash,
diff --git a/program/src/processor/fraud_proofs/raise_challenge.rs b/program/src/processor/fraud_proofs/raise_challenge.rs
index 5427ae2e..0849a78a 100644
--- a/program/src/processor/fraud_proofs/raise_challenge.rs
+++ b/program/src/processor/fraud_proofs/raise_challenge.rs
@@ -81,13 +81,13 @@ pub fn process_raise_challenge(
)?;
let pending_account_pubkey = *pending_state.account_pubkey();
- let commit_id_bytes = pending_state.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending_state.commit_seq().to_le_bytes();
let challenge_bump = require_uninitialized_pda(
challenge,
&[
CHALLENGE_SEED,
pending_account_pubkey.as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
challenger.address().as_ref(),
],
&crate::fast::ID,
@@ -128,7 +128,7 @@ pub fn process_raise_challenge(
&[Signer::from(&[
Seed::from(CHALLENGE_SEED),
Seed::from(pending_account_pubkey.as_ref()),
- Seed::from(&commit_id_bytes),
+ Seed::from(&commit_seq_bytes),
Seed::from(challenger.address().as_ref()),
Seed::from(&[challenge_bump]),
])],
@@ -194,13 +194,13 @@ fn validate_pending_commitment(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending_commitment.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending_commitment.commit_seq().to_le_bytes();
require_initialized_pda(
pending_commitment_account,
&[
PENDING_COMMITMENT_SEED,
pending_commitment.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
],
&crate::fast::ID,
true,
diff --git a/program/src/processor/fraud_proofs/resolve_dispute.rs b/program/src/processor/fraud_proofs/resolve_dispute.rs
index 0862aa9c..fb6fad36 100644
--- a/program/src/processor/fraud_proofs/resolve_dispute.rs
+++ b/program/src/processor/fraud_proofs/resolve_dispute.rs
@@ -254,13 +254,13 @@ fn validate_pending_commitment(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending.commit_seq().to_le_bytes();
require_initialized_pda(
pending_commitment,
&[
PENDING_COMMITMENT_SEED,
pending.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
],
&crate::fast::ID,
true,
@@ -300,13 +300,13 @@ fn validate_challenge(
return Err(ProgramError::InvalidAccountData);
}
- let commit_id_bytes = pending.commit_id().to_le_bytes();
+ let commit_seq_bytes = pending.commit_seq().to_le_bytes();
require_initialized_pda(
challenge,
&[
CHALLENGE_SEED,
pending.account_pubkey().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
challenger.address().as_ref(),
],
&crate::fast::ID,
diff --git a/program/src/processor/fraud_proofs/write_state_buffer.rs b/program/src/processor/fraud_proofs/write_state_buffer.rs
index 7d025459..54363e59 100644
--- a/program/src/processor/fraud_proofs/write_state_buffer.rs
+++ b/program/src/processor/fraud_proofs/write_state_buffer.rs
@@ -50,11 +50,11 @@ pub fn process_write_state_buffer(
let args = WriteStateBufferArgs::decode(data)?;
let (offset, write_end) = validate_args(&args)?;
- let commit_id_bytes = args.commit_id().to_le_bytes();
+ let commit_seq_bytes = args.commit_seq().to_le_bytes();
let state_buffer_seeds = [
STATE_BUFFER_SEED,
delegated_account.address().as_ref(),
- &commit_id_bytes,
+ &commit_seq_bytes,
authority.address().as_ref(),
];
@@ -98,7 +98,7 @@ pub fn process_write_state_buffer(
&[Signer::from(&[
Seed::from(STATE_BUFFER_SEED),
Seed::from(delegated_account.address().as_ref()),
- Seed::from(&commit_id_bytes),
+ Seed::from(&commit_seq_bytes),
Seed::from(authority.address().as_ref()),
Seed::from(&[state_buffer_bump]),
])],
@@ -109,7 +109,7 @@ pub fn process_write_state_buffer(
discriminator: StateBuffer::DISCRIMINATOR,
authority: *authority.address(),
account_pubkey: *delegated_account.address(),
- commit_id: args.commit_id(),
+ commit_seq: args.commit_seq(),
data_hash: [0; 32],
total_len: args.total_len(),
finalized: false,
@@ -274,8 +274,8 @@ fn validate_state_buffer(
ProgramError::InvalidAccountData
);
require_eq!(
- state.commit_id(),
- args.commit_id(),
+ state.commit_seq(),
+ args.commit_seq(),
ProgramError::InvalidInstructionData
);
require_eq!(
diff --git a/program/src/processor/mod.rs b/program/src/processor/mod.rs
index ed630dbb..11fbba97 100644
--- a/program/src/processor/mod.rs
+++ b/program/src/processor/mod.rs
@@ -1,8 +1,10 @@
use delegation_program_interface as dpi;
mod bootstrap;
+mod delegate;
mod fraud_proofs;
pub use bootstrap::*;
+pub use delegate::*;
use dpi::DlpV2Instruction;
pub use fraud_proofs::*;
use pinocchio::{AccountView, ProgramResult};
@@ -50,5 +52,6 @@ pub fn process_instruction(
DlpV2Instruction::ResolveDispute => {
process_resolve_dispute(accounts, data)
}
+ DlpV2Instruction::Delegate => process_delegate(accounts, data),
}
}
diff --git a/program/tests/test_approve_commitment.rs b/program/tests/test_approve_commitment.rs
index 800195ba..c340eb79 100644
--- a/program/tests/test_approve_commitment.rs
+++ b/program/tests/test_approve_commitment.rs
@@ -56,7 +56,7 @@ async fn test_approve_commitment() {
&env.verifiers[0],
env.delegation_cluster,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
)
.await
.unwrap();
@@ -64,7 +64,7 @@ async fn test_approve_commitment() {
let pending_commitment_data = read_pending_commitment_data(
&mut env.banks,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
)
.await;
let pending_commitment =
@@ -103,7 +103,7 @@ async fn test_approve_commitment_duplicate_is_noop() {
&env.verifiers[0],
env.delegation_cluster,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
)
.await
.unwrap();
@@ -113,7 +113,7 @@ async fn test_approve_commitment_duplicate_is_noop() {
&env.verifiers[0],
env.delegation_cluster,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
)
.await
.unwrap();
@@ -121,7 +121,7 @@ async fn test_approve_commitment_duplicate_is_noop() {
let pending_commitment_data = read_pending_commitment_data(
&mut env.banks,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
)
.await;
let pending_commitment =
@@ -157,7 +157,7 @@ async fn test_approve_commitment_fails_with_wrong_verifier() {
&env.verifiers[1],
env.delegation_cluster,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
)
.await
.is_err());
@@ -183,7 +183,7 @@ async fn test_approve_commitment_fails_without_verifier_signature() {
env.verifiers[0].pubkey(),
env.delegation_cluster,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
);
ix.accounts[0].is_signer = false;
@@ -218,7 +218,7 @@ async fn test_approve_commitment_fails_with_instruction_data() {
env.verifiers[0].pubkey(),
env.delegation_cluster,
env.delegated_account,
- args.commit_id,
+ args.commit_seq,
);
ix.data.push(1);
@@ -355,7 +355,7 @@ async fn setup_approve_commitment_env(
&operator,
delegated_account,
WriteStateBufferArgs {
- commit_id: propose_commitment_args().commit_id,
+ commit_seq: propose_commitment_args().commit_seq,
total_len: state_data().len() as u32,
offset: 0,
chunk: state_data(),
@@ -456,7 +456,7 @@ async fn register_and_add_verifier(
fn propose_commitment_args() -> ProposeCommitmentArgs {
ProposeCommitmentArgs {
- commit_id: 1,
+ commit_seq: 1,
lamports: 1_000,
owner: Pubkey::new_from_array([7; 32]),
da_pointer_hash: [9; 32],
@@ -527,7 +527,7 @@ async fn approve(
verifier: &Keypair,
delegation_cluster: Pubkey,
delegated_account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
) -> Result<(), solana_program_test::BanksClientError> {
let latest_blockhash: Hash = banks.get_latest_blockhash().await.unwrap();
let blockhash = banks
@@ -538,7 +538,7 @@ async fn approve(
verifier.pubkey(),
delegation_cluster,
delegated_account,
- commit_id,
+ commit_seq,
);
let tx = Transaction::new_signed_with_payer(
&[ix],
@@ -553,10 +553,10 @@ async fn approve(
async fn read_pending_commitment_data(
banks: &mut BanksClient,
delegated_account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
) -> Vec {
let pending_commitment_account = banks
- .get_account(pending_commitment_pda(&delegated_account, commit_id))
+ .get_account(pending_commitment_pda(&delegated_account, commit_seq))
.await
.unwrap()
.unwrap();
diff --git a/program/tests/test_challenger_reveal.rs b/program/tests/test_challenger_reveal.rs
index 511cad62..63b7be46 100644
--- a/program/tests/test_challenger_reveal.rs
+++ b/program/tests/test_challenger_reveal.rs
@@ -102,7 +102,7 @@ async fn test_challenger_reveal_matching_state_penalizes_and_reopens_commitment(
challenge.challenger_state_buffer,
state_buffer_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
&env.challenger.pubkey()
)
);
@@ -271,12 +271,12 @@ async fn test_challenger_reveal_fails_with_wrong_challenger_buffer() {
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
reveal_args,
);
ix.accounts[4].pubkey = state_buffer_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
&env.operator.pubkey(),
);
@@ -296,11 +296,11 @@ async fn test_challenger_reveal_fails_with_unfinalized_challenger_buffer() {
env.committed_owner,
account_data_hash(&expected_data),
);
- let commit_id = env.commit_id;
+ let commit_seq = env.commit_seq;
write_challenger_state_buffer_args(
&mut env,
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: expected_data.len() as u32,
offset: 0,
chunk: expected_data[..2].to_vec(),
@@ -339,7 +339,7 @@ async fn test_challenger_reveal_fails_with_wrong_fee_vault() {
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
reveal_args,
);
ix.accounts[6].pubkey = env.challenger.pubkey();
@@ -358,7 +358,7 @@ struct ChallengerRevealEnv {
delegated_account: Pubkey,
committed_owner: Pubkey,
committed_lamports: u64,
- commit_id: u64,
+ commit_seq: u32,
challenge_config: ChallengeConfig,
operator_state_data: Vec,
}
@@ -378,7 +378,7 @@ async fn setup_challenger_reveal_env() -> ChallengerRevealEnv {
let delegation_cluster =
dpi::pda::delegation_cluster_pda(&cluster_identity.pubkey());
let committed_owner = Pubkey::new_unique();
- let commit_id = 1;
+ let commit_seq = 1;
let operator_state_data = vec![9, 8, 7, 6, 5];
let record_lamports = LAMPORTS_PER_SOL;
let committed_lamports = LAMPORTS_PER_SOL;
@@ -464,7 +464,7 @@ async fn setup_challenger_reveal_env() -> ChallengerRevealEnv {
&operator,
delegated_account,
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: operator_state_data.len() as u32,
offset: 0,
chunk: operator_state_data.clone(),
@@ -482,7 +482,7 @@ async fn setup_challenger_reveal_env() -> ChallengerRevealEnv {
delegated_account,
committed_owner,
committed_lamports,
- commit_id,
+ commit_seq,
challenge_config,
operator_state_data,
}
@@ -496,7 +496,7 @@ async fn propose(
env.delegation_cluster,
env.delegated_account,
ProposeCommitmentArgs {
- commit_id: env.commit_id,
+ commit_seq: env.commit_seq,
lamports: env.committed_lamports,
owner: env.committed_owner,
da_pointer_hash: [9; 32],
@@ -517,7 +517,7 @@ async fn raise_for_reveal(
env.challenger.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
RaiseChallengeArgs {
state_commitment_hash: pending.state_commitment_hash,
challenge_hash: challenge_hash(
@@ -525,7 +525,7 @@ async fn raise_for_reveal(
env.operator.pubkey(),
env.challenger.pubkey(),
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
reveal_args,
),
stake_lamports,
@@ -544,7 +544,7 @@ async fn reveal(
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
args,
);
@@ -558,7 +558,7 @@ async fn write_challenger_state_buffer(
write_challenger_state_buffer_args(
env,
WriteStateBufferArgs {
- commit_id: env.commit_id,
+ commit_seq: env.commit_seq,
total_len: data.len() as u32,
offset: 0,
chunk: data,
@@ -684,7 +684,7 @@ async fn read_pending_commitment(
.banks_client
.get_account(pending_commitment_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
))
.await
.unwrap()
@@ -790,7 +790,7 @@ fn valid_reveal_args(
fn challenge_address(env: &ChallengerRevealEnv) -> Pubkey {
challenge_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
&env.challenger.pubkey(),
)
}
@@ -805,7 +805,7 @@ fn challenge_hash(
operator: Pubkey,
challenger: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
args: &ChallengerRevealArgs,
) -> [u8; 32] {
solana_sha256_hasher::hashv(&[
@@ -814,7 +814,7 @@ fn challenge_hash(
operator.as_ref(),
challenger.as_ref(),
account.as_ref(),
- &commit_id.to_le_bytes(),
+ &commit_seq.to_le_bytes(),
&args.lamports.to_le_bytes(),
args.owner.as_ref(),
&args.data_hash,
diff --git a/program/tests/test_finalize_commitment.rs b/program/tests/test_finalize_commitment.rs
index af254148..28d51c07 100644
--- a/program/tests/test_finalize_commitment.rs
+++ b/program/tests/test_finalize_commitment.rs
@@ -70,7 +70,10 @@ async fn test_finalize_commitment() {
assert_eq!(delegation_record.lamports, env.committed_lamports);
let delegation_metadata = read_delegation_metadata(&mut env).await;
- assert_eq!(delegation_metadata.last_commit_id, env.commit_id);
+ assert_eq!(
+ delegation_metadata.last_commit_id,
+ u64::from(env.commit_seq)
+ );
}
#[tokio::test]
@@ -111,7 +114,7 @@ async fn test_finalize_commitment_fails_with_wrong_operator() {
wrong_operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
assert!(process_ix(&mut env.context, ix, &[&wrong_operator])
@@ -226,7 +229,7 @@ struct FinalizeCommitmentEnv {
delegated_account: Pubkey,
committed_owner: Pubkey,
committed_lamports: u64,
- commit_id: u64,
+ commit_seq: u32,
final_state_data: Vec,
}
@@ -248,7 +251,7 @@ async fn setup_finalize_commitment_env(
dpi::pda::delegation_cluster_pda(&cluster_identity.pubkey());
let account_owner = Pubkey::new_unique();
let committed_owner = account_owner;
- let commit_id = 1;
+ let commit_seq = 1;
let final_state_data = vec![9, 8, 7, 6, 5];
add_lamport_account(&mut program_test, authority.pubkey());
@@ -330,7 +333,7 @@ async fn setup_finalize_commitment_env(
&operator,
delegated_account,
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: final_state_data.len() as u32,
offset: 0,
chunk: final_state_data.clone(),
@@ -347,7 +350,7 @@ async fn setup_finalize_commitment_env(
delegated_account,
committed_owner,
committed_lamports,
- commit_id,
+ commit_seq,
final_state_data,
}
}
@@ -360,7 +363,7 @@ async fn propose(
env.delegation_cluster,
env.delegated_account,
ProposeCommitmentArgs {
- commit_id: env.commit_id,
+ commit_seq: env.commit_seq,
lamports: env.committed_lamports,
owner: env.committed_owner,
da_pointer_hash: [9; 32],
@@ -378,7 +381,7 @@ async fn approve(
env.verifier.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
process_ix(&mut env.context, ix, &[&env.verifier]).await
@@ -391,7 +394,7 @@ async fn finalize(
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
process_ix(&mut env.context, ix, &[&env.operator]).await
@@ -506,7 +509,7 @@ async fn read_pending_commitment(
.banks_client
.get_account(pending_commitment_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
))
.await
.unwrap()
diff --git a/program/tests/test_primary_delegate.rs b/program/tests/test_primary_delegate.rs
new file mode 100644
index 00000000..1ac4a668
--- /dev/null
+++ b/program/tests/test_primary_delegate.rs
@@ -0,0 +1,362 @@
+use delegation_program::solana_program;
+use delegation_program_interface as dpi;
+use dpi::{
+ instruction_builder::delegate,
+ legacy::pda::DELEGATE_BUFFER_TAG,
+ pda::{delegation_state_pda, DELEGATION_STATE_SEED},
+ DelegateArgs, DelegationSeed, DelegationState, UndelegationRequester,
+};
+use solana_program::{
+ account_info::AccountInfo,
+ entrypoint::ProgramResult,
+ instruction::{AccountMeta, Instruction},
+ native_token::LAMPORTS_PER_SOL,
+ program::invoke_signed,
+ program_error::ProgramError,
+ pubkey::Pubkey,
+ rent::Rent,
+};
+use solana_program_test::{
+ processor, BanksClient, BanksClientError, ProgramTest,
+};
+use solana_sdk::{
+ account::Account,
+ instruction::InstructionError,
+ signature::{Keypair, Signer},
+ transaction::{Transaction, TransactionError},
+};
+use solana_sdk_ids::system_program;
+use wheels::layout::Decodable;
+
+#[allow(dead_code)]
+mod fixtures;
+
+use crate::fixtures::v2::{direct_cluster_args, initialize_delegation_cluster};
+
+const OWNER_PROGRAM_ID: Pubkey =
+ solana_sdk::pubkey!("4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4EVRtnYHk");
+const DELEGATED_ACCOUNT_SEED: &[u8] = b"primary-delegated";
+const DELEGATED_ACCOUNT_DATA: &[u8] = b"primary account data";
+const DELEGATE_BUFFER_DATA: &[u8] = b"delegate buffer data";
+
+struct DelegateTestContext {
+ banks: BanksClient,
+ payer: Keypair,
+ delegated_account: Pubkey,
+ delegated_account_bump: u8,
+ delegation_cluster: Pubkey,
+}
+
+#[tokio::test]
+async fn test_delegate_creates_cluster_bound_delegation_state() {
+ let context = setup_delegate_test().await;
+ let delegation_state =
+ delegation_state_pda(&context.delegated_account.to_bytes().into());
+ let (_, expected_state_bump) = Pubkey::find_program_address(
+ &[DELEGATION_STATE_SEED, context.delegated_account.as_ref()],
+ &dpi::id(),
+ );
+
+ let result = submit_delegate(
+ &context,
+ DelegateArgs::new(
+ context.delegated_account_bump,
+ vec![DelegationSeed {
+ value: DELEGATED_ACCOUNT_SEED.to_vec(),
+ }],
+ ),
+ )
+ .await;
+ assert!(result.is_ok());
+
+ let delegated_account = context
+ .banks
+ .get_account(context.delegated_account)
+ .await
+ .unwrap()
+ .unwrap();
+ assert_eq!(delegated_account.owner, dpi::id());
+ assert_eq!(delegated_account.data, DELEGATE_BUFFER_DATA);
+
+ let state_account = context
+ .banks
+ .get_account(delegation_state)
+ .await
+ .unwrap()
+ .unwrap();
+ let state = DelegationState::decode(&state_account.data).unwrap();
+ let seeds = state.seeds().unwrap();
+
+ assert_eq!(state.discriminator(), DelegationState::DISCRIMINATOR);
+ assert_eq!(state.bump(), expected_state_bump);
+ assert_eq!(*state.delegated_account(), context.delegated_account);
+ assert_eq!(*state.delegation_cluster(), context.delegation_cluster);
+ assert_eq!(*state.original_owner(), OWNER_PROGRAM_ID);
+ assert_eq!(*state.rent_payer(), context.payer.pubkey());
+ assert_eq!(state.lamports(), delegated_account.lamports);
+ assert_eq!(state.last_commit_seq(), 0);
+ assert_eq!(
+ state.undelegation_requester(),
+ UndelegationRequester::None.value()
+ );
+ assert_eq!(
+ state.delegated_account_bump(),
+ context.delegated_account_bump
+ );
+ assert_eq!(seeds.len(), 1);
+ assert_eq!(seeds.get(0).unwrap().as_slice(), DELEGATED_ACCOUNT_SEED);
+ assert_eq!(
+ state_account.lamports,
+ Rent::default().minimum_balance(state_account.data.len())
+ );
+}
+
+#[tokio::test]
+async fn test_delegate_rejects_wrong_delegated_account_seeds() {
+ let context = setup_delegate_test().await;
+ let result = submit_delegate(
+ &context,
+ DelegateArgs::new(
+ context.delegated_account_bump,
+ vec![DelegationSeed {
+ value: b"wrong-seed".to_vec(),
+ }],
+ ),
+ )
+ .await;
+
+ assert!(
+ matches!(
+ &result,
+ Err(BanksClientError::TransactionError(
+ TransactionError::InstructionError(
+ 0,
+ InstructionError::InvalidSeeds
+ )
+ ))
+ ),
+ "unexpected result: {result:?}"
+ );
+ assert!(context
+ .banks
+ .get_account(delegation_state_pda(
+ &context.delegated_account.to_bytes().into()
+ ))
+ .await
+ .unwrap()
+ .is_none());
+}
+
+#[tokio::test]
+async fn test_delegate_rejects_non_system_owner_for_on_curve_account() {
+ let mut program_test = ProgramTest::default();
+ program_test.prefer_bpf(true);
+ program_test.add_program("delegation_program", dpi::ID, None);
+
+ let delegated_account = Keypair::new();
+ let config_authority = Keypair::new();
+ program_test.add_account(
+ delegated_account.pubkey(),
+ Account {
+ lamports: Rent::default().minimum_balance(0),
+ data: vec![],
+ owner: dpi::id(),
+ executable: false,
+ rent_epoch: 0,
+ },
+ );
+ program_test.add_account(
+ config_authority.pubkey(),
+ Account {
+ lamports: LAMPORTS_PER_SOL,
+ data: vec![],
+ owner: system_program::id(),
+ executable: false,
+ rent_epoch: 0,
+ },
+ );
+
+ let (banks, payer, blockhash) = program_test.start().await;
+ let delegation_cluster = initialize_delegation_cluster(
+ &banks,
+ &payer,
+ &config_authority,
+ blockhash,
+ direct_cluster_args(Pubkey::new_unique()),
+ )
+ .await;
+ let instruction = delegate(
+ payer.pubkey(),
+ delegated_account.pubkey(),
+ OWNER_PROGRAM_ID,
+ delegation_cluster,
+ DelegateArgs::new(0, vec![]),
+ )
+ .unwrap();
+ let transaction = Transaction::new_signed_with_payer(
+ &[instruction],
+ Some(&payer.pubkey()),
+ &[&payer, &delegated_account],
+ banks.get_latest_blockhash().await.unwrap(),
+ );
+ let result = banks.process_transaction(transaction).await;
+
+ assert!(
+ matches!(
+ &result,
+ Err(BanksClientError::TransactionError(
+ TransactionError::InstructionError(
+ 0,
+ InstructionError::IncorrectProgramId
+ )
+ ))
+ ),
+ "unexpected result: {result:?}"
+ );
+}
+
+async fn setup_delegate_test() -> DelegateTestContext {
+ let mut program_test = ProgramTest::default();
+ program_test.prefer_bpf(true);
+ program_test.add_program("delegation_program", dpi::ID, None);
+ program_test.prefer_bpf(false);
+ program_test.add_program(
+ "primary-delegate-owner",
+ OWNER_PROGRAM_ID,
+ processor!(owner_program_processor),
+ );
+ program_test.prefer_bpf(true);
+
+ let (delegated_account, delegated_account_bump) =
+ Pubkey::find_program_address(
+ &[DELEGATED_ACCOUNT_SEED],
+ &OWNER_PROGRAM_ID,
+ );
+ let delegate_buffer = Pubkey::find_program_address(
+ &[DELEGATE_BUFFER_TAG, delegated_account.as_ref()],
+ &OWNER_PROGRAM_ID,
+ )
+ .0;
+ let config_authority = Keypair::new();
+
+ program_test.add_account(
+ delegated_account,
+ Account {
+ lamports: Rent::default()
+ .minimum_balance(DELEGATED_ACCOUNT_DATA.len()),
+ data: DELEGATED_ACCOUNT_DATA.to_vec(),
+ owner: dpi::id(),
+ executable: false,
+ rent_epoch: 0,
+ },
+ );
+ program_test.add_account(
+ delegate_buffer,
+ Account {
+ lamports: Rent::default()
+ .minimum_balance(DELEGATE_BUFFER_DATA.len()),
+ data: DELEGATE_BUFFER_DATA.to_vec(),
+ owner: OWNER_PROGRAM_ID,
+ executable: false,
+ rent_epoch: 0,
+ },
+ );
+ program_test.add_account(
+ config_authority.pubkey(),
+ Account {
+ lamports: LAMPORTS_PER_SOL,
+ data: vec![],
+ owner: system_program::id(),
+ executable: false,
+ rent_epoch: 0,
+ },
+ );
+
+ let (banks, payer, blockhash) = program_test.start().await;
+ let delegation_cluster = initialize_delegation_cluster(
+ &banks,
+ &payer,
+ &config_authority,
+ blockhash,
+ direct_cluster_args(Pubkey::new_unique()),
+ )
+ .await;
+
+ DelegateTestContext {
+ banks,
+ payer,
+ delegated_account,
+ delegated_account_bump,
+ delegation_cluster,
+ }
+}
+
+async fn submit_delegate(
+ context: &DelegateTestContext,
+ args: DelegateArgs,
+) -> Result<(), solana_program_test::BanksClientError> {
+ let inner = delegate(
+ context.payer.pubkey(),
+ context.delegated_account,
+ OWNER_PROGRAM_ID,
+ context.delegation_cluster,
+ args,
+ )
+ .unwrap();
+ let mut accounts = inner.accounts;
+ accounts[1].is_signer = false;
+ accounts.push(AccountMeta::new_readonly(dpi::id(), false));
+ let outer = Instruction {
+ program_id: OWNER_PROGRAM_ID,
+ accounts,
+ data: inner.data,
+ };
+ let transaction = Transaction::new_signed_with_payer(
+ &[outer],
+ Some(&context.payer.pubkey()),
+ &[&context.payer],
+ context.banks.get_latest_blockhash().await.unwrap(),
+ );
+
+ context.banks.process_transaction(transaction).await
+}
+
+fn owner_program_processor(
+ program_id: &Pubkey,
+ accounts: &[AccountInfo],
+ data: &[u8],
+) -> ProgramResult {
+ let [payer, delegated_account, original_owner, delegate_buffer, delegation_state, delegation_cluster, system_program, dlp_program] =
+ accounts
+ else {
+ return Err(ProgramError::NotEnoughAccountKeys);
+ };
+ if original_owner.key != program_id || dlp_program.key != &dpi::id() {
+ return Err(ProgramError::IncorrectProgramId);
+ }
+
+ let instruction = Instruction {
+ program_id: dpi::id(),
+ accounts: vec![
+ AccountMeta::new(*payer.key, true),
+ AccountMeta::new(*delegated_account.key, true),
+ AccountMeta::new_readonly(*original_owner.key, false),
+ AccountMeta::new(*delegate_buffer.key, false),
+ AccountMeta::new(*delegation_state.key, false),
+ AccountMeta::new_readonly(*delegation_cluster.key, false),
+ AccountMeta::new_readonly(*system_program.key, false),
+ ],
+ data: data.to_vec(),
+ };
+ let delegated_account_bump =
+ [
+ Pubkey::find_program_address(&[DELEGATED_ACCOUNT_SEED], program_id)
+ .1,
+ ];
+
+ invoke_signed(
+ &instruction,
+ accounts,
+ &[&[DELEGATED_ACCOUNT_SEED, &delegated_account_bump]],
+ )
+}
diff --git a/program/tests/test_propose_commitment.rs b/program/tests/test_propose_commitment.rs
index 8eedb7b9..d453f4f8 100644
--- a/program/tests/test_propose_commitment.rs
+++ b/program/tests/test_propose_commitment.rs
@@ -55,7 +55,7 @@ async fn test_propose_commitment() {
.banks
.get_account(pending_commitment_pda(
&env.delegated_account,
- args.commit_id,
+ args.commit_seq,
))
.await
.unwrap()
@@ -82,7 +82,7 @@ async fn test_propose_commitment() {
env.operator.pubkey()
);
assert_eq!(*pending_commitment.account_pubkey(), env.delegated_account);
- assert_eq!(pending_commitment.commit_id(), args.commit_id);
+ assert_eq!(pending_commitment.commit_seq(), args.commit_seq);
assert_eq!(pending_commitment.lamports(), args.lamports);
assert_eq!(*pending_commitment.owner(), args.owner);
assert_eq!(
@@ -231,7 +231,7 @@ async fn test_propose_commitment_fails_without_state_buffer() {
})
.await;
let mut args = propose_commitment_args();
- args.commit_id = 99;
+ args.commit_seq = 99;
assert!(propose(&mut env, args).await.is_err());
}
@@ -264,7 +264,7 @@ async fn test_propose_commitment_rejects_wrong_owner() {
}
#[tokio::test]
-async fn test_propose_commitment_rejects_out_of_order_commit_id() {
+async fn test_propose_commitment_rejects_out_of_order_commit_seq() {
let mut env = setup_propose_commitment_env(ProposeCommitmentSetup {
verifier_count: 2,
register_operator_as_verifier: true,
@@ -272,14 +272,14 @@ async fn test_propose_commitment_rejects_out_of_order_commit_id() {
})
.await;
let mut args = propose_commitment_args();
- args.commit_id = 2;
+ args.commit_seq = 2;
write_state(
&mut env.banks,
&env.payer,
&env.operator,
env.delegated_account,
WriteStateBufferArgs {
- commit_id: args.commit_id,
+ commit_seq: args.commit_seq,
total_len: state_data().len() as u32,
offset: 0,
chunk: state_data(),
@@ -442,7 +442,7 @@ async fn setup_propose_commitment_env(
&operator,
delegated_account,
WriteStateBufferArgs {
- commit_id: propose_commitment_args().commit_id,
+ commit_seq: propose_commitment_args().commit_seq,
total_len: state_data().len() as u32,
offset: 0,
chunk: state_data(),
@@ -545,7 +545,7 @@ async fn register_and_add_verifier(
fn propose_commitment_args() -> ProposeCommitmentArgs {
ProposeCommitmentArgs {
- commit_id: 1,
+ commit_seq: 1,
lamports: 1_000,
owner: Pubkey::new_from_array([7; 32]),
da_pointer_hash: [9; 32],
diff --git a/program/tests/test_raise_challenge.rs b/program/tests/test_raise_challenge.rs
index 01593483..4c832e1f 100644
--- a/program/tests/test_raise_challenge.rs
+++ b/program/tests/test_raise_challenge.rs
@@ -50,7 +50,7 @@ async fn test_raise_challenge() {
let args = valid_raise_challenge_args(pending_before.state_commitment_hash);
let challenge_address = challenge_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
&env.challenger.pubkey(),
);
@@ -71,7 +71,7 @@ async fn test_raise_challenge() {
assert_eq!(challenge.outcome(), CHALLENGE_OUTCOME_NONE);
assert_eq!(
*challenge.pending_commitment(),
- pending_commitment_pda(&env.delegated_account, env.commit_id)
+ pending_commitment_pda(&env.delegated_account, env.commit_seq)
);
assert_eq!(*challenge.challenger_identity(), env.challenger.pubkey());
assert_eq!(
@@ -114,7 +114,7 @@ async fn test_raise_challenge_fails_without_challenger_signature() {
env.challenger.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
args,
);
ix.accounts[0].is_signer = false;
@@ -164,7 +164,7 @@ async fn test_raise_challenge_uses_submitted_policy() {
.banks_client
.get_account(challenge_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
&env.challenger.pubkey(),
))
.await
@@ -238,7 +238,7 @@ struct RaiseChallengeEnv {
delegated_account: Pubkey,
committed_owner: Pubkey,
committed_lamports: u64,
- commit_id: u64,
+ commit_seq: u32,
challenge_config: ChallengeConfig,
}
@@ -257,7 +257,7 @@ async fn setup_raise_challenge_env() -> RaiseChallengeEnv {
let delegation_cluster =
dpi::pda::delegation_cluster_pda(&cluster_identity.pubkey());
let committed_owner = Pubkey::new_unique();
- let commit_id = 1;
+ let commit_seq = 1;
let final_state_data = vec![9, 8, 7, 6, 5];
let record_lamports = LAMPORTS_PER_SOL;
let committed_lamports = LAMPORTS_PER_SOL;
@@ -342,7 +342,7 @@ async fn setup_raise_challenge_env() -> RaiseChallengeEnv {
&operator,
delegated_account,
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: final_state_data.len() as u32,
offset: 0,
chunk: final_state_data.clone(),
@@ -361,7 +361,7 @@ async fn setup_raise_challenge_env() -> RaiseChallengeEnv {
delegated_account,
committed_owner,
committed_lamports,
- commit_id,
+ commit_seq,
challenge_config,
}
}
@@ -372,7 +372,7 @@ async fn propose(env: &mut RaiseChallengeEnv) -> Result<(), BanksClientError> {
env.delegation_cluster,
env.delegated_account,
ProposeCommitmentArgs {
- commit_id: env.commit_id,
+ commit_seq: env.commit_seq,
lamports: env.committed_lamports,
owner: env.committed_owner,
da_pointer_hash: [9; 32],
@@ -388,7 +388,7 @@ async fn approve(env: &mut RaiseChallengeEnv) -> Result<(), BanksClientError> {
env.verifier.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
process_ix(&mut env.context, ix, &[&env.verifier]).await
@@ -402,7 +402,7 @@ async fn raise(
env.challenger.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
args,
);
@@ -414,7 +414,7 @@ async fn finalize(env: &mut RaiseChallengeEnv) -> Result<(), BanksClientError> {
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
process_ix(&mut env.context, ix, &[&env.operator]).await
@@ -531,7 +531,7 @@ async fn read_pending_commitment(
.banks_client
.get_account(pending_commitment_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
))
.await
.unwrap()
diff --git a/program/tests/test_resolve_dispute.rs b/program/tests/test_resolve_dispute.rs
index 8f96de71..b865d8a1 100644
--- a/program/tests/test_resolve_dispute.rs
+++ b/program/tests/test_resolve_dispute.rs
@@ -131,7 +131,7 @@ async fn test_resolve_dispute_operator_correct_slashes_challenger_and_selects_op
env.challenger.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
assert!(process_ix(&mut env.context, ix, &[&env.challenger])
.await
@@ -141,7 +141,7 @@ async fn test_resolve_dispute_operator_correct_slashes_challenger_and_selects_op
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
process_ix(&mut env.context, ix, &[&env.operator])
.await
@@ -227,7 +227,7 @@ async fn test_resolve_dispute_challenger_correct_refunds_challenger_and_slashes_
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
assert!(process_ix(&mut env.context, ix, &[&env.operator])
.await
@@ -237,7 +237,7 @@ async fn test_resolve_dispute_challenger_correct_refunds_challenger_and_slashes_
env.challenger.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
);
process_ix(&mut env.context, ix, &[&env.challenger])
.await
@@ -269,7 +269,7 @@ async fn test_resolve_dispute_fails_with_wrong_resolver() {
env.delegation_cluster,
env.challenger.pubkey(),
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
ResolveDisputeArgs {
decision: DISPUTE_DECISION_OPERATOR_STATE_CORRECT,
},
@@ -321,7 +321,7 @@ async fn test_resolve_dispute_fails_with_wrong_operator_bond() {
env.delegation_cluster,
env.challenger.pubkey(),
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
ResolveDisputeArgs {
decision: DISPUTE_DECISION_OPERATOR_STATE_CORRECT,
},
@@ -343,7 +343,7 @@ async fn test_resolve_dispute_fails_with_wrong_fee_vault() {
env.delegation_cluster,
env.challenger.pubkey(),
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
ResolveDisputeArgs {
decision: DISPUTE_DECISION_OPERATOR_STATE_CORRECT,
},
@@ -375,7 +375,7 @@ struct ResolveDisputeEnv {
delegated_account: Pubkey,
committed_owner: Pubkey,
committed_lamports: u64,
- commit_id: u64,
+ commit_seq: u32,
challenge_config: ChallengeConfig,
operator_state_data: Vec,
challenger_state_data: Vec,
@@ -401,7 +401,7 @@ async fn setup_resolve_dispute_env() -> ResolveDisputeEnv {
dpi::pda::delegation_cluster_pda(&cluster_identity.pubkey());
let challenge_config = cluster_args.challenge_config.clone().unwrap();
let committed_owner = Pubkey::new_unique();
- let commit_id = 1;
+ let commit_seq = 1;
let operator_state_data = vec![9, 8, 7, 6, 5];
let challenger_state_data = vec![4, 3, 2, 1];
let record_lamports = LAMPORTS_PER_SOL;
@@ -492,7 +492,7 @@ async fn setup_resolve_dispute_env() -> ResolveDisputeEnv {
&operator,
delegated_account,
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: operator_state_data.len() as u32,
offset: 0,
chunk: operator_state_data.clone(),
@@ -511,7 +511,7 @@ async fn setup_resolve_dispute_env() -> ResolveDisputeEnv {
delegated_account,
committed_owner,
committed_lamports,
- commit_id,
+ commit_seq,
challenge_config,
operator_state_data,
challenger_state_data,
@@ -549,7 +549,7 @@ async fn propose(env: &mut ResolveDisputeEnv) -> Result<(), BanksClientError> {
env.delegation_cluster,
env.delegated_account,
ProposeCommitmentArgs {
- commit_id: env.commit_id,
+ commit_seq: env.commit_seq,
lamports: env.committed_lamports,
owner: env.committed_owner,
da_pointer_hash: [9; 32],
@@ -570,7 +570,7 @@ async fn raise_for_reveal(
env.challenger.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
RaiseChallengeArgs {
state_commitment_hash: pending.state_commitment_hash,
challenge_hash: challenge_hash(
@@ -578,7 +578,7 @@ async fn raise_for_reveal(
env.operator.pubkey(),
env.challenger.pubkey(),
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
reveal_args,
),
stake_lamports,
@@ -597,7 +597,7 @@ async fn reveal(
env.operator.pubkey(),
env.delegation_cluster,
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
args,
);
@@ -613,7 +613,7 @@ async fn resolve(
env.delegation_cluster,
env.challenger.pubkey(),
env.delegated_account,
- env.commit_id,
+ env.commit_seq,
args,
);
@@ -629,7 +629,7 @@ async fn write_challenger_state_buffer(
&env.challenger,
env.delegated_account,
WriteStateBufferArgs {
- commit_id: env.commit_id,
+ commit_seq: env.commit_seq,
total_len: data.len() as u32,
offset: 0,
chunk: data,
@@ -742,7 +742,7 @@ async fn read_pending_commitment(
.banks_client
.get_account(pending_commitment_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
))
.await
.unwrap()
@@ -867,7 +867,7 @@ fn valid_reveal_args(
fn challenge_address(env: &ResolveDisputeEnv) -> Pubkey {
challenge_pda(
&env.delegated_account,
- env.commit_id,
+ env.commit_seq,
&env.challenger.pubkey(),
)
}
@@ -882,7 +882,7 @@ fn challenge_hash(
operator: Pubkey,
challenger: Pubkey,
account: Pubkey,
- commit_id: u64,
+ commit_seq: u32,
args: &ChallengerRevealArgs,
) -> [u8; 32] {
solana_sha256_hasher::hashv(&[
@@ -891,7 +891,7 @@ fn challenge_hash(
operator.as_ref(),
challenger.as_ref(),
account.as_ref(),
- &commit_id.to_le_bytes(),
+ &commit_seq.to_le_bytes(),
&args.lamports.to_le_bytes(),
args.owner.as_ref(),
&args.data_hash,
diff --git a/program/tests/test_v2_write_state_buffer.rs b/program/tests/test_v2_write_state_buffer.rs
index 96113fa2..6d6b99b0 100644
--- a/program/tests/test_v2_write_state_buffer.rs
+++ b/program/tests/test_v2_write_state_buffer.rs
@@ -23,7 +23,7 @@ use crate::fixtures::v2::setup_program_test_env;
#[tokio::test]
async fn test_write_state_buffer_unregistered_authority_one_chunk_finalizes() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 7;
+ let commit_seq = 7;
let data = vec![1, 2, 3, 4];
write_buffer(
@@ -32,7 +32,7 @@ async fn test_write_state_buffer_unregistered_authority_one_chunk_finalizes() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: data.len() as u32,
offset: 0,
chunk: data.clone(),
@@ -43,7 +43,7 @@ async fn test_write_state_buffer_unregistered_authority_one_chunk_finalizes() {
let state_buffer = state_buffer_pda(
&env.delegated.pubkey(),
- commit_id,
+ commit_seq,
&env.writer.pubkey(),
);
let state_buffer_account =
@@ -53,7 +53,7 @@ async fn test_write_state_buffer_unregistered_authority_one_chunk_finalizes() {
assert_eq!(state.discriminator(), StateBuffer::DISCRIMINATOR);
assert_eq!(*state.authority(), env.writer.pubkey());
assert_eq!(*state.account_pubkey(), env.delegated.pubkey());
- assert_eq!(state.commit_id(), commit_id);
+ assert_eq!(state.commit_seq(), commit_seq);
assert_eq!(state.total_len(), data.len() as u32);
assert!(state.finalized());
assert_eq!(*state.data_hash(), account_data_hash(&data));
@@ -69,7 +69,7 @@ async fn test_write_state_buffer_unregistered_authority_one_chunk_finalizes() {
#[tokio::test]
async fn test_write_state_buffer_empty_payload_finalizes() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 16;
+ let commit_seq = 16;
write_buffer(
&mut env.banks,
@@ -77,7 +77,7 @@ async fn test_write_state_buffer_empty_payload_finalizes() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: 0,
offset: 0,
chunk: vec![],
@@ -88,7 +88,7 @@ async fn test_write_state_buffer_empty_payload_finalizes() {
let state_buffer = state_buffer_pda(
&env.delegated.pubkey(),
- commit_id,
+ commit_seq,
&env.writer.pubkey(),
);
let state_buffer_account =
@@ -109,11 +109,11 @@ async fn test_write_state_buffer_empty_payload_finalizes() {
#[tokio::test]
async fn test_write_state_buffer_multiple_chunks_finalize() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 8;
+ let commit_seq = 8;
let total_len = 5;
let state_buffer = state_buffer_pda(
&env.delegated.pubkey(),
- commit_id,
+ commit_seq,
&env.writer.pubkey(),
);
@@ -124,7 +124,7 @@ async fn test_write_state_buffer_multiple_chunks_finalize() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len,
offset: 0,
chunk: vec![1, 2],
@@ -167,7 +167,7 @@ async fn test_write_state_buffer_multiple_chunks_finalize() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len,
offset: 2,
chunk: vec![3, 4, 5],
@@ -198,10 +198,10 @@ async fn test_write_state_buffer_multiple_chunks_finalize() {
#[tokio::test]
async fn test_write_state_buffer_grows_payload_span_past_initial_capacity() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 15;
+ let commit_seq = 15;
let state_buffer = state_buffer_pda(
&env.delegated.pubkey(),
- commit_id,
+ commit_seq,
&env.writer.pubkey(),
);
let initial_payload_capacity = StateBuffer::MAX_INITIAL_PAYLOAD_LEN;
@@ -227,7 +227,7 @@ async fn test_write_state_buffer_grows_payload_span_past_initial_capacity() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: total_len as u32,
offset: offset as u32,
chunk,
@@ -272,7 +272,7 @@ async fn test_write_state_buffer_grows_payload_span_past_initial_capacity() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: total_len as u32,
offset: first_write_len as u32,
chunk: crossing_chunk.clone(),
@@ -306,7 +306,7 @@ async fn test_write_state_buffer_grows_payload_span_past_initial_capacity() {
#[tokio::test]
async fn test_write_state_buffer_duplicate_retry() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 9;
+ let commit_seq = 9;
let first_chunk = vec![1, 2];
write_buffer(
@@ -315,7 +315,7 @@ async fn test_write_state_buffer_duplicate_retry() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: 4,
offset: 0,
chunk: first_chunk.clone(),
@@ -330,7 +330,7 @@ async fn test_write_state_buffer_duplicate_retry() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: 4,
offset: 0,
chunk: first_chunk,
@@ -341,7 +341,7 @@ async fn test_write_state_buffer_duplicate_retry() {
let state_buffer = state_buffer_pda(
&env.delegated.pubkey(),
- commit_id,
+ commit_seq,
&env.writer.pubkey(),
);
let state_buffer_account =
@@ -368,7 +368,7 @@ async fn test_write_state_buffer_duplicate_retry() {
#[tokio::test]
async fn test_write_state_buffer_rejects_mismatched_duplicate_retry() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 10;
+ let commit_seq = 10;
write_buffer(
&mut env.banks,
@@ -376,7 +376,7 @@ async fn test_write_state_buffer_rejects_mismatched_duplicate_retry() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: 4,
offset: 0,
chunk: vec![1, 2],
@@ -391,7 +391,7 @@ async fn test_write_state_buffer_rejects_mismatched_duplicate_retry() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: 4,
offset: 0,
chunk: vec![1, 9],
@@ -412,7 +412,7 @@ async fn test_write_state_buffer_rejects_wrong_offset() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id: 11,
+ commit_seq: 11,
total_len: 4,
offset: 1,
chunk: vec![1, 2],
@@ -433,7 +433,7 @@ async fn test_write_state_buffer_rejects_oversized_total_len() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id: 12,
+ commit_seq: 12,
total_len: StateBuffer::MAX_TOTAL_PAYLOAD_LEN + 1,
offset: 0,
chunk: vec![1],
@@ -447,7 +447,7 @@ async fn test_write_state_buffer_rejects_oversized_total_len() {
#[tokio::test]
async fn test_write_state_buffer_rejects_post_finalize_mutation() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 13;
+ let commit_seq = 13;
let data = vec![1, 2, 3];
write_buffer(
@@ -456,7 +456,7 @@ async fn test_write_state_buffer_rejects_post_finalize_mutation() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: data.len() as u32,
offset: 0,
chunk: data.clone(),
@@ -471,7 +471,7 @@ async fn test_write_state_buffer_rejects_post_finalize_mutation() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: data.len() as u32,
offset: 0,
chunk: data,
@@ -486,7 +486,7 @@ async fn test_write_state_buffer_rejects_post_finalize_mutation() {
&env.writer,
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: 3,
offset: 3,
chunk: vec![4],
@@ -500,7 +500,7 @@ async fn test_write_state_buffer_rejects_post_finalize_mutation() {
#[tokio::test]
async fn test_write_state_buffer_rejects_wrong_authority_for_buffer() {
let mut env = setup_write_state_buffer_env().await;
- let commit_id = 14;
+ let commit_seq = 14;
let wrong_authority = Keypair::new();
fund_account(&mut env.banks, &env.payer, &wrong_authority.pubkey()).await;
@@ -509,7 +509,7 @@ async fn test_write_state_buffer_rejects_wrong_authority_for_buffer() {
env.writer.pubkey(),
env.delegated.pubkey(),
WriteStateBufferArgs {
- commit_id,
+ commit_seq,
total_len: 2,
offset: 0,
chunk: vec![1, 2],