0.5.1-pre.002
This commit is contained in:
281
ks-lib/src/executor/spl/elgamal_registry/builder.rs
Normal file
281
ks-lib/src/executor/spl/elgamal_registry/builder.rs
Normal file
@@ -0,0 +1,281 @@
|
||||
// file: ks-lib/src/executor/spl/elgamal_registry/builder.rs
|
||||
// version: 8
|
||||
|
||||
//! Official registry builders and conservative plan validation.
|
||||
|
||||
use base64::Engine; // rust-rules: trait-import
|
||||
use std::str::FromStr; // rust-rules: trait-import
|
||||
|
||||
pub(crate) fn executor_spl_elgamal_registry_build_prepared_plan(
|
||||
intent: &crate::ExSplElgamalRegistryExecutionIntent,
|
||||
) -> ks_core::Result<crate::ExApiPreparedExecutionPlan> {
|
||||
if intent.intent_id.trim().is_empty() {
|
||||
return std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_intent_id_empty",
|
||||
"ElGamal registry execution intent id must not be empty",
|
||||
));
|
||||
}
|
||||
if intent.policy.simulation != crate::ExApiExecutionSimulationPolicy::Required {
|
||||
return std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_simulation_required",
|
||||
"ElGamal registry execution requires simulation",
|
||||
));
|
||||
}
|
||||
match intent.policy.cost_limit.max_fee_lamports {
|
||||
std::option::Option::Some(value) if value > 0 => {},
|
||||
std::option::Option::Some(_) | std::option::Option::None => {
|
||||
return std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_fee_limit_missing",
|
||||
"ElGamal registry execution requires a positive fee ceiling",
|
||||
));
|
||||
},
|
||||
}
|
||||
let validation = &intent.policy.post_execution_validation;
|
||||
if !validation.canonical_insert_required
|
||||
|| !validation.core_extraction_required
|
||||
|| !validation.decode_replay_required
|
||||
|| !validation.materialization_required
|
||||
{
|
||||
return std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_post_validation_required",
|
||||
"ElGamal registry execution requires canonical insert, core extraction, decode replay and materialization",
|
||||
));
|
||||
}
|
||||
let fee_payer = match parse_address(&intent.fee_payer, "fee_payer") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let (owner_model, proof, operation_code, create) = match &intent.operation {
|
||||
crate::ExSplElgamalRegistryOperation::CreateRegistry { owner, proof } => {
|
||||
(owner, proof, crate::EX_SPL_ELGAMAL_REGISTRY_CREATE_OPERATION, true)
|
||||
},
|
||||
crate::ExSplElgamalRegistryOperation::UpdateRegistry { owner, proof } => {
|
||||
(owner, proof, crate::EX_SPL_ELGAMAL_REGISTRY_UPDATE_OPERATION, false)
|
||||
},
|
||||
};
|
||||
let owner = match parse_address(owner_model, "owner") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let instructions = match proof {
|
||||
crate::ExSplElgamalRegistryProofLocation::ContextStateAccount { account } => {
|
||||
let context = match parse_address(account, "context_state_account") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let location = spl_token_confidential_transfer_proof_extraction::instruction::ProofLocation::ContextStateAccount(&context);
|
||||
build_official(create, &owner, location)
|
||||
},
|
||||
crate::ExSplElgamalRegistryProofLocation::Inline { proof_data_base64 } => {
|
||||
let bytes = match base64::engine::general_purpose::STANDARD
|
||||
.decode(proof_data_base64.as_bytes())
|
||||
{
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_proof_base64_invalid",
|
||||
error.to_string(),
|
||||
));
|
||||
},
|
||||
};
|
||||
let expected = std::mem::size_of::<
|
||||
solana_zk_elgamal_proof_interface::proof_data::PubkeyValidityProofData,
|
||||
>();
|
||||
if bytes.len() != expected {
|
||||
return std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_proof_size_invalid",
|
||||
format!(
|
||||
"PubkeyValidityProofData requires {expected} bytes, received {}",
|
||||
bytes.len()
|
||||
),
|
||||
));
|
||||
}
|
||||
let proof_data = bytemuck::pod_read_unaligned::<
|
||||
solana_zk_elgamal_proof_interface::proof_data::PubkeyValidityProofData,
|
||||
>(bytes.as_slice());
|
||||
let offset = match std::num::NonZeroI8::new(1) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_internal_offset_invalid",
|
||||
"inline proof offset must be one",
|
||||
));
|
||||
},
|
||||
};
|
||||
let location = spl_token_confidential_transfer_proof_extraction::instruction::ProofLocation::InstructionOffset(offset, &proof_data);
|
||||
build_official(create, &owner, location)
|
||||
},
|
||||
};
|
||||
let instructions: Vec<solana_instruction::Instruction> = match instructions {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let planned: Vec<crate::ExApiPlannedInstruction> = instructions
|
||||
.iter()
|
||||
.map(|instruction| return planned_instruction(operation_code, instruction))
|
||||
.collect();
|
||||
let mut required_signers = vec![crate::ExApiRequiredSigner {
|
||||
pubkey: intent.fee_payer.clone(),
|
||||
role: std::string::String::from("fee_payer"),
|
||||
}];
|
||||
if intent.fee_payer != *owner_model {
|
||||
required_signers.push(crate::ExApiRequiredSigner {
|
||||
pubkey: owner_model.clone(),
|
||||
role: std::string::String::from("registry_owner"),
|
||||
});
|
||||
}
|
||||
tracing::debug!(
|
||||
target: crate::TRACING_TARGET_EXECUTOR_SPL_ELGAMAL_REGISTRY,
|
||||
action = "build_prepared_plan",
|
||||
intent_id = %intent.intent_id,
|
||||
operation_code,
|
||||
owner = %owner_model.0,
|
||||
instruction_count = planned.len(),
|
||||
"built SPL ElGamal registry execution plan"
|
||||
);
|
||||
return std::result::Result::Ok(crate::ExApiPreparedExecutionPlan {
|
||||
executor_name: std::string::String::from("kb-lib.executor.spl.elgamal_registry"),
|
||||
executor_version: std::string::String::from(env!("CARGO_PKG_VERSION")),
|
||||
intent_id: intent.intent_id.clone(),
|
||||
operation_code: std::string::String::from(operation_code),
|
||||
fee_payer: crate::MdPubkey(fee_payer.to_string()),
|
||||
instructions: planned,
|
||||
required_signers,
|
||||
policy: intent.policy.clone(),
|
||||
requested_spend_lamports: 0,
|
||||
requested_compute_unit_price_micro_lamports: std::option::Option::None,
|
||||
});
|
||||
}
|
||||
|
||||
fn build_official(
|
||||
create: bool,
|
||||
owner: &solana_pubkey::Pubkey,
|
||||
location: spl_token_confidential_transfer_proof_extraction::instruction::ProofLocation<
|
||||
solana_zk_elgamal_proof_interface::proof_data::PubkeyValidityProofData,
|
||||
>,
|
||||
) -> ks_core::Result<std::vec::Vec<solana_instruction::Instruction>> {
|
||||
let result = if create {
|
||||
spl_elgamal_registry_interface::instruction::create_registry(owner, location)
|
||||
} else {
|
||||
spl_elgamal_registry_interface::instruction::update_registry(owner, location)
|
||||
};
|
||||
return match result {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_builder_failed",
|
||||
error.to_string(),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_address(value: &crate::MdPubkey, field: &str) -> ks_core::Result<solana_pubkey::Pubkey> {
|
||||
return match solana_pubkey::Pubkey::from_str(value.0.as_str()) {
|
||||
std::result::Result::Ok(address) => std::result::Result::Ok(address),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_spl_elgamal_registry_pubkey_invalid",
|
||||
format!("{field}: {error}"),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
fn planned_instruction(
|
||||
operation_code: &str,
|
||||
instruction: &solana_instruction::Instruction,
|
||||
) -> crate::ExApiPlannedInstruction {
|
||||
return crate::ExApiPlannedInstruction {
|
||||
program_id: crate::MdProgramId(instruction.program_id.to_string()),
|
||||
operation_code: std::string::String::from(operation_code),
|
||||
accounts: instruction
|
||||
.accounts
|
||||
.iter()
|
||||
.map(|account| {
|
||||
return crate::ExApiPlannedAccount {
|
||||
pubkey: crate::MdPubkey(account.pubkey.to_string()),
|
||||
is_signer: account.is_signer,
|
||||
is_writable: account.is_writable,
|
||||
};
|
||||
})
|
||||
.collect(),
|
||||
data: instruction.data.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn pubkey(value: &str) -> crate::MdPubkey {
|
||||
return crate::MdPubkey(std::string::String::from(value));
|
||||
}
|
||||
|
||||
fn intent(create: bool) -> crate::ExSplElgamalRegistryExecutionIntent {
|
||||
let owner = pubkey(ks_program_ids::SYSTEM_PROGRAM_ID);
|
||||
return crate::ExSplElgamalRegistryExecutionIntent {
|
||||
intent_id: std::string::String::from("registry-intent"),
|
||||
fee_payer: owner.clone(),
|
||||
policy: crate::ExApiExecutionPolicy {
|
||||
cost_limit: crate::ExApiExecutionCostLimit {
|
||||
max_spend_lamports: std::option::Option::Some(0),
|
||||
max_fee_lamports: std::option::Option::Some(20_000),
|
||||
max_compute_unit_price_micro_lamports: std::option::Option::None,
|
||||
},
|
||||
authorized_signers: vec![owner.clone()],
|
||||
dry_run: true,
|
||||
post_execution_validation: crate::ExApiPostExecutionValidationPolicy {
|
||||
canonical_insert_required: true,
|
||||
core_extraction_required: true,
|
||||
decode_replay_required: true,
|
||||
materialization_required: true,
|
||||
},
|
||||
..crate::ExApiExecutionPolicy::default()
|
||||
},
|
||||
operation: if create {
|
||||
crate::ExSplElgamalRegistryOperation::CreateRegistry {
|
||||
owner,
|
||||
proof: crate::ExSplElgamalRegistryProofLocation::ContextStateAccount {
|
||||
account: pubkey(ks_program_ids::VOTE_PROGRAM_ID),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
crate::ExSplElgamalRegistryOperation::UpdateRegistry {
|
||||
owner,
|
||||
proof: crate::ExSplElgamalRegistryProofLocation::ContextStateAccount {
|
||||
account: pubkey(ks_program_ids::VOTE_PROGRAM_ID),
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_and_update_use_official_registry_wire_and_accounts() {
|
||||
for create in [true, false] {
|
||||
let plan = crate::executor_spl_elgamal_registry_build_prepared_plan(&intent(create))
|
||||
.unwrap_or_else(|error| panic!("registry plan failed: {error}"));
|
||||
assert_eq!(plan.instructions.len(), 1);
|
||||
assert_eq!(
|
||||
plan.instructions[0].program_id.0,
|
||||
ks_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID
|
||||
);
|
||||
assert_eq!(plan.instructions[0].data, if create { vec![0, 0] } else { vec![1, 0] });
|
||||
assert_eq!(plan.required_signers.len(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn optional_simulation_and_invalid_inline_proof_fail_closed() {
|
||||
let mut value = intent(true);
|
||||
value.policy.simulation = crate::ExApiExecutionSimulationPolicy::Optional;
|
||||
let error = crate::executor_spl_elgamal_registry_build_prepared_plan(&value)
|
||||
.expect_err("optional simulation must fail");
|
||||
assert_eq!(error.code(), "execution_spl_elgamal_registry_simulation_required");
|
||||
value = intent(true);
|
||||
value.operation = crate::ExSplElgamalRegistryOperation::CreateRegistry {
|
||||
owner: pubkey(ks_program_ids::SYSTEM_PROGRAM_ID),
|
||||
proof: crate::ExSplElgamalRegistryProofLocation::Inline {
|
||||
proof_data_base64: std::string::String::from("AA=="),
|
||||
},
|
||||
};
|
||||
let error = crate::executor_spl_elgamal_registry_build_prepared_plan(&value)
|
||||
.expect_err("invalid proof size must fail");
|
||||
assert_eq!(error.code(), "execution_spl_elgamal_registry_proof_size_invalid");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user