From a092f80dd3219f6afb7de5df9b5932bec397cdf0 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Tue, 9 Apr 2024 20:58:23 -0400 Subject: [PATCH] use hash to identify policies (#39) * use hash to identify policies * use policy account in hash --- programs/Cargo.lock | 114 ++++++++++++++++++ programs/policy_engine/Cargo.toml | 1 + programs/policy_engine/src/error.rs | 2 + .../policy_engine/src/instructions/attach.rs | 3 +- .../policy_engine/src/instructions/create.rs | 2 + .../policy_engine/src/instructions/detach.rs | 4 +- programs/policy_engine/src/lib.rs | 4 +- programs/policy_engine/src/state/account.rs | 50 ++++++-- 8 files changed, 168 insertions(+), 12 deletions(-) diff --git a/programs/Cargo.lock b/programs/Cargo.lock index 2305fa3..c9c3ef4 100644 --- a/programs/Cargo.lock +++ b/programs/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.4.3" @@ -378,6 +393,17 @@ dependencies = [ "spl-transfer-hook-interface 0.5.1", ] +[[package]] +name = "async-trait" +version = "0.1.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "atty" version = "0.2.14" @@ -395,6 +421,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.12.3" @@ -626,6 +667,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + [[package]] name = "cc" version = "1.0.90" @@ -958,6 +1005,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "hashbrown" version = "0.11.2" @@ -1000,6 +1053,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hmac" version = "0.8.1" @@ -1242,6 +1301,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -1335,6 +1403,15 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -1400,6 +1477,12 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + [[package]] name = "policy_engine" version = "0.0.1" @@ -1407,6 +1490,7 @@ dependencies = [ "anchor-lang", "anchor-spl", "num_enum 0.7.2", + "sha256", ] [[package]] @@ -1631,6 +1715,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1756,6 +1846,19 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha256" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0" +dependencies = [ + "async-trait", + "bytes", + "hex", + "sha2 0.10.8", + "tokio", +] + [[package]] name = "sha3" version = "0.9.1" @@ -2367,6 +2470,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "pin-project-lite", +] + [[package]] name = "toml" version = "0.5.11" diff --git a/programs/policy_engine/Cargo.toml b/programs/policy_engine/Cargo.toml index da1d023..89eaf0d 100644 --- a/programs/policy_engine/Cargo.toml +++ b/programs/policy_engine/Cargo.toml @@ -19,3 +19,4 @@ default = [] anchor-lang = { git = "https://git@github.com/bridgesplit/anchor" } anchor-spl = { git = "https://git@github.com/bridgesplit/anchor" } num_enum = "0.7.2" +sha256 = "1.5.0" diff --git a/programs/policy_engine/src/error.rs b/programs/policy_engine/src/error.rs index 169c8b4..61cb82a 100644 --- a/programs/policy_engine/src/error.rs +++ b/programs/policy_engine/src/error.rs @@ -18,4 +18,6 @@ pub enum PolicyEngineErrors { IdentityFilterFailed, #[msg("Unauthorized signer")] UnauthorizedSigner, + #[msg("Policy already exists")] + PolicyAlreadyExists, } diff --git a/programs/policy_engine/src/instructions/attach.rs b/programs/policy_engine/src/instructions/attach.rs index 1f23999..c20d61f 100644 --- a/programs/policy_engine/src/instructions/attach.rs +++ b/programs/policy_engine/src/instructions/attach.rs @@ -30,9 +30,10 @@ pub fn handler( identity_filter: IdentityFilter, policy_type: PolicyType, ) -> Result<()> { + let policy_account_address = ctx.accounts.policy_account.key(); ctx.accounts .policy_account - .attach(policy_type, identity_filter); + .attach(policy_account_address, policy_type, identity_filter)?; ctx.accounts.policy_engine.update_max_timeframe(policy_type); Ok(()) } diff --git a/programs/policy_engine/src/instructions/create.rs b/programs/policy_engine/src/instructions/create.rs index e4e867c..29f1fdf 100644 --- a/programs/policy_engine/src/instructions/create.rs +++ b/programs/policy_engine/src/instructions/create.rs @@ -29,7 +29,9 @@ pub fn handler( identity_filter: IdentityFilter, policy_type: PolicyType, ) -> Result<()> { + let policy_account_address = ctx.accounts.policy_account.key(); ctx.accounts.policy_account.new( + policy_account_address, ctx.accounts.policy_engine.key(), identity_filter, policy_type, diff --git a/programs/policy_engine/src/instructions/detach.rs b/programs/policy_engine/src/instructions/detach.rs index 5730b6e..595dc72 100644 --- a/programs/policy_engine/src/instructions/detach.rs +++ b/programs/policy_engine/src/instructions/detach.rs @@ -25,8 +25,8 @@ pub struct DetachFromPolicyAccount<'info> { pub system_program: Program<'info, System>, } -pub fn handler(ctx: Context, policy_type: PolicyType) -> Result<()> { - ctx.accounts.policy_account.detach(policy_type); +pub fn handler(ctx: Context, hash: String) -> Result<()> { + let policy_type = ctx.accounts.policy_account.detach(hash)?; // update max timeframe if detached policy was the max timeframe let mut max_timeframe = match policy_type { diff --git a/programs/policy_engine/src/lib.rs b/programs/policy_engine/src/lib.rs index b42a299..8054be1 100644 --- a/programs/policy_engine/src/lib.rs +++ b/programs/policy_engine/src/lib.rs @@ -47,8 +47,8 @@ pub mod policy_engine { /// remove policy pub fn detach_from_policy_account( ctx: Context, - policy_type: PolicyType, + hash: String, ) -> Result<()> { - instructions::detach::handler(ctx, policy_type) + instructions::detach::handler(ctx, hash) } } diff --git a/programs/policy_engine/src/state/account.rs b/programs/policy_engine/src/state/account.rs index 1c559de..82a55ac 100644 --- a/programs/policy_engine/src/state/account.rs +++ b/programs/policy_engine/src/state/account.rs @@ -1,14 +1,16 @@ pub use anchor_lang::prelude::*; use num_enum::IntoPrimitive; -#[derive(AnchorDeserialize, AnchorSerialize, Clone, InitSpace, Copy)] +use crate::PolicyEngineErrors; + +#[derive(AnchorDeserialize, AnchorSerialize, Clone, InitSpace, Copy, Debug)] pub struct IdentityFilter { pub identity_levels: [u8; 10], pub comparision_type: ComparisionType, } #[repr(u8)] -#[derive(IntoPrimitive, AnchorDeserialize, AnchorSerialize, Clone, InitSpace, Copy)] +#[derive(IntoPrimitive, AnchorDeserialize, AnchorSerialize, Clone, InitSpace, Copy, Debug)] pub enum ComparisionType { Or, And, @@ -27,11 +29,13 @@ pub struct PolicyAccount { #[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace)] pub struct Policy { + #[max_len(32)] + pub hash: String, pub policy_type: PolicyType, pub identity_filter: IdentityFilter, } -#[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace, PartialEq, Copy)] +#[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace, PartialEq, Copy, Debug)] pub enum PolicyType { IdentityApproval, TransactionAmountLimit { limit: u64 }, @@ -40,8 +44,18 @@ pub enum PolicyType { } impl PolicyAccount { + fn hash_policy( + policy_account: Pubkey, + policy_type: PolicyType, + identity_filter: IdentityFilter, + ) -> String { + let hash = format!("{:?}{:?}{:?}", policy_account, policy_type, identity_filter); + sha256::digest(hash.as_bytes()) + } + /// hash pub fn new( &mut self, + policy_account: Pubkey, policy_engine: Pubkey, identity_filter: IdentityFilter, policy_type: PolicyType, @@ -49,19 +63,41 @@ impl PolicyAccount { self.version = 1; self.policy_engine = policy_engine; self.policies = vec![Policy { + hash: Self::hash_policy(policy_account, policy_type, identity_filter), policy_type, identity_filter, }]; } - pub fn attach(&mut self, policy_type: PolicyType, identity_filter: IdentityFilter) { + pub fn attach( + &mut self, + policy_account: Pubkey, + policy_type: PolicyType, + identity_filter: IdentityFilter, + ) -> Result<()> { + let hash = Self::hash_policy(policy_account, policy_type, identity_filter); + if self.policies.iter().any(|policy| policy.hash == hash) { + return Err(PolicyEngineErrors::PolicyAlreadyExists.into()); + } self.policies.push(Policy { + hash, policy_type, identity_filter, }); + Ok(()) } - pub fn detach(&mut self, policy_type: PolicyType) { - self.policies - .retain(|policy| policy.policy_type != policy_type); + pub fn detach(&mut self, hash: String) -> Result { + if self.policies.iter().all(|policy| policy.hash != hash) { + return Err(PolicyEngineErrors::PolicyNotFound.into()); + } + // remove and return the policy type + let policy_type = self + .policies + .iter() + .find(|policy| policy.hash == hash) + .unwrap() // safe to unwrap as we checked the policy exists + .policy_type; + self.policies.retain(|policy| policy.hash != hash); + Ok(policy_type) } }