From b0ddeecb83ec9ac87ea975a379e8fe50fb0c7d81 Mon Sep 17 00:00:00 2001 From: Nino Lipartiia Date: Thu, 15 Dec 2022 16:13:01 +0200 Subject: [PATCH 1/4] Tick deletes only active agents --- contracts/cw-croncat/src/manager.rs | 17 ++-- contracts/cw-croncat/src/tests/manager.rs | 106 +++++++++++++++++++++- 2 files changed, 113 insertions(+), 10 deletions(-) diff --git a/contracts/cw-croncat/src/manager.rs b/contracts/cw-croncat/src/manager.rs index fb85c704..1e04d48b 100644 --- a/contracts/cw-croncat/src/manager.rs +++ b/contracts/cw-croncat/src/manager.rs @@ -3,7 +3,8 @@ use crate::error::ContractError; use crate::helpers::proxy_call_submsgs_price; use crate::state::{Config, CwCroncat, QueueItem, TaskInfo}; use cosmwasm_std::{ - from_binary, Addr, Deps, DepsMut, Env, MessageInfo, Order, Reply, Response, StdResult, Storage, + from_binary, Addr, Attribute, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, + Storage, }; use cw_croncat_core::traits::{FindAndMutate, Intervals}; use cw_croncat_core::types::{Agent, Interval, SlotType, Task}; @@ -528,11 +529,8 @@ impl<'a> CwCroncat<'a> { let cfg = self.config.load(deps.storage)?; let mut attributes = vec![]; let mut submessages = vec![]; - for agent_id in self - .agents - .keys(deps.storage, None, None, Order::Ascending) - .collect::>>()? - { + + for agent_id in self.agent_active_queue.load(deps.storage)? { let agent = self.agents.load(deps.storage, &agent_id)?; if current_slot > agent.last_executed_slot + cfg.agents_eject_threshold { let resp = self @@ -543,6 +541,13 @@ impl<'a> CwCroncat<'a> { submessages.extend_from_slice(&resp.messages); } } + + // Check if there isn't any active or pending agents + if self.agent_active_queue.load(deps.storage)?.is_empty() + && self.agent_pending_queue.is_empty(deps.storage)? + { + attributes.push(Attribute::new("lifecycle", "tick_failure")) + } let response = Response::new() .add_attribute("method", "tick") .add_attributes(attributes) diff --git a/contracts/cw-croncat/src/tests/manager.rs b/contracts/cw-croncat/src/tests/manager.rs index ea4d3487..0a669587 100644 --- a/contracts/cw-croncat/src/tests/manager.rs +++ b/contracts/cw-croncat/src/tests/manager.rs @@ -1,7 +1,7 @@ use crate::contract::{GAS_ACTION_FEE_JUNO, GAS_BASE_FEE_JUNO, GAS_DENOMINATOR_DEFAULT_JUNO}; use crate::tests::helpers::{ add_1000_blocks, add_little_time, add_one_duration_of_time, cw4_template, proper_instantiate, - AGENT3, + AGENT1, AGENT2, AGENT3, }; use crate::ContractError; use cosmwasm_std::{ @@ -1854,7 +1854,7 @@ fn tick() { owner_id: None, agent_fee: None, min_tasks_per_agent: None, - agents_eject_threshold: Some(1000), // allow to miss 100 slots + agents_eject_threshold: Some(1000), // allow to miss 1000 slots gas_action_fee: None, proxy_callback_gas: None, slot_granularity_time: None, @@ -1876,10 +1876,61 @@ fn tick() { app.execute_contract(Addr::unchecked(AGENT0), contract_addr.clone(), &msg, &[]) .unwrap(); + // Add 1001 blocks and call tick + app.update_block(add_1000_blocks); + app.update_block(add_little_time); + let tick_msg = ExecuteMsg::Tick {}; + let res = app + .execute_contract( + Addr::unchecked(ANYONE), + contract_addr.clone(), + &tick_msg, + &vec![], + ) + .unwrap(); + + // Check attributes + assert!(res.events.iter().any(|ev| ev + .attributes + .iter() + .any(|attr| attr.key == "method" && attr.value == "tick"))); + assert!(res.events.iter().any(|ev| ev + .attributes + .iter() + .any(|attr| attr.key == "method" && attr.value == "unregister_agent"))); + assert!(res.events.iter().any(|ev| ev + .attributes + .iter() + .any(|attr| attr.key == "account_id" && attr.value == AGENT0))); + assert!(res.events.iter().any(|ev| ev + .attributes + .iter() + .any(|attr| attr.key == "lifecycle" && attr.value == "tick_failure"))); + + // The agent missed 1001 blocks and he was unregistered + // Pending agents weren't deleted + let agents: GetAgentIdsResponse = app + .wrap() + .query_wasm_smart(contract_addr.clone(), &QueryMsg::GetAgentIds {}) + .unwrap(); + assert!(agents.active.is_empty()); + assert!(agents.pending.is_empty()); + + // quick agent register + app.execute_contract(Addr::unchecked(AGENT0), contract_addr.clone(), &msg, &[]) + .unwrap(); + + // Two agents added to the pending queue + app.execute_contract(Addr::unchecked(AGENT1), contract_addr.clone(), &msg, &[]) + .unwrap(); + app.execute_contract(Addr::unchecked(AGENT2), contract_addr.clone(), &msg, &[]) + .unwrap(); + // need block advancement app.update_block(add_little_time); - let tick_msg = ExecuteMsg::Tick {}; + // Call tick + // Not enough time passed to delete the agent let res = app .execute_contract( Addr::unchecked(AGENT0), @@ -1904,7 +1955,25 @@ fn tick() { .query_wasm_smart(contract_addr.clone(), &QueryMsg::GetAgentIds {}) .unwrap(); assert_eq!(agents.active.len(), 1); + assert_eq!(agents.pending.len(), 2); + // First pending agent wasn't nominated + let err = app + .execute_contract( + Addr::unchecked(AGENT1), + contract_addr.clone(), + &ExecuteMsg::CheckInAgent {}, + &[], + ) + .unwrap_err(); + assert_eq!( + ContractError::CustomError { + val: "Not accepting new agents".to_string() + }, + err.downcast().unwrap() + ); + + // Add enough time and call tick app.update_block(add_1000_blocks); let res = app .execute_contract( @@ -1928,14 +1997,43 @@ fn tick() { .attributes .iter() .any(|attr| attr.key == "account_id" && attr.value == AGENT0))); + assert!(!res.events.iter().any(|ev| ev + .attributes + .iter() + .any(|attr| attr.key == "lifecycle" && attr.value == "tick_failure"))); // The agent missed 1001 blocks and he was unregistered + // Pending agents weren't deleted let agents: GetAgentIdsResponse = app .wrap() .query_wasm_smart(contract_addr.clone(), &QueryMsg::GetAgentIds {}) .unwrap(); assert!(agents.active.is_empty()); - assert!(agents.pending.is_empty()); + assert_eq!(agents.pending.len(), 2); + + // First agent was nominated and can call CheckInAgent + app.execute_contract( + Addr::unchecked(AGENT1), + contract_addr.clone(), + &ExecuteMsg::CheckInAgent {}, + &[], + ) + .unwrap(); + // Second agent wasn't nominated + let err = app + .execute_contract( + Addr::unchecked(AGENT2), + contract_addr.clone(), + &ExecuteMsg::CheckInAgent {}, + &[], + ) + .unwrap_err(); + assert_eq!( + ContractError::CustomError { + val: "Not accepting new agents".to_string() + }, + err.downcast().unwrap() + ); } #[test] From e52b3d97bca24b95d793d22a2a1515036057bf38 Mon Sep 17 00:00:00 2001 From: Nino Lipartiia Date: Thu, 15 Dec 2022 17:49:47 +0200 Subject: [PATCH 2/4] checksum --- checksum | 2 -- 1 file changed, 2 deletions(-) diff --git a/checksum b/checksum index 36487034..e69de29b 100644 --- a/checksum +++ b/checksum @@ -1,2 +0,0 @@ -efc374eee9ede4a11ec6c344db13de10afdfd10510cb70f39611e2c67c20a58b cw_croncat.wasm -5863a5417a530690c765c9ca4f3943c96071b1ee7faecfc408fce01da08aec56 cw_rules.wasm From fa9b6cad04eb23277c8977066b37616cf862d152 Mon Sep 17 00:00:00 2001 From: Nino Lipartiia Date: Thu, 15 Dec 2022 22:55:27 +0200 Subject: [PATCH 3/4] checksum should be correct --- checksum | 2 ++ 1 file changed, 2 insertions(+) diff --git a/checksum b/checksum index e69de29b..61b0bbb2 100644 --- a/checksum +++ b/checksum @@ -0,0 +1,2 @@ +0b7413fb3c3809fa748d4dbb501f6b69427eb54e2123fc8f5e51ab5531cc1771 cw_croncat.wasm +5863a5417a530690c765c9ca4f3943c96071b1ee7faecfc408fce01da08aec56 cw_rules.wasm From 2e02ae1d3b844ba3e032c8c56e7fd7f1440f8767 Mon Sep 17 00:00:00 2001 From: Nino Lipartiia Date: Sat, 17 Dec 2022 00:53:48 +0200 Subject: [PATCH 4/4] checksum --- checksum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checksum b/checksum index 780448df..f4b34c56 100644 --- a/checksum +++ b/checksum @@ -1,2 +1,2 @@ -0b7413fb3c3809fa748d4dbb501f6b69427eb54e2123fc8f5e51ab5531cc1771 cw_croncat.wasm -5863a5417a530690c765c9ca4f3943c96071b1ee7faecfc408fce01da08aec56 cw_rules.wasm \ No newline at end of file +14994ed3c237597f9ece434ce72387cd04525ff5b27a90909f9d881cae4d96db cw_croncat.wasm +de2d1a0c648e41760020dd261f818da085c358240059acf85128f60eb0e05db2 cw_rules.wasm