Created
October 26, 2025 09:07
-
-
Save tindzk/e53772c940ac0fb2e3e886b0431c21e3 to your computer and use it in GitHub Desktop.
Actor proposal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| enum AccountActorMsg { | |
| MempoolEvent(MempoolEvent), | |
| TxStarted(TransactionId), | |
| TxCompleted(TransactionId), | |
| Shutdown, | |
| } | |
| pub struct AccountActor { | |
| mode: ActorMode, | |
| origin: AccountOrigin, | |
| active: HashMap<TransactionId, MempoolEvent>, | |
| state: NetworkAccountState, | |
| } | |
| impl AccountActor { | |
| pub fn on_message(&mut self, msg: AccountActorMsg, ctx: ActorContext) { | |
| match (msg, self.mode) { | |
| AccountActorMsg::MempoolEvent(MempoolEvent::TransactionAdded { id, .. }) => { | |
| self.active.insert(id, event.clone()); | |
| ctx.send::<ChainActor>(ChainActorMsg::ProcessTx { | |
| account: self.origin.clone(), | |
| id, | |
| }); | |
| }, | |
| AccountActorMsg::MempoolEvent(event) => { | |
| self.state.mempool_update(event); | |
| }, | |
| AccountActorMsg::TxStarted(id) => { | |
| // TODO Log event if already processing a transaction | |
| self.mode = ActorMode::ProcessingTx(id); | |
| }, | |
| AccountActorMsg::TxCompleted(id) => { | |
| if let Some(event) = self.active.get(&id) { | |
| if let Some(reason) = self.state.mempool_update(event) { | |
| // Failure occurred | |
| ctx.stop(); | |
| } else { | |
| self.mode = ActorMode::Idle; | |
| } | |
| } | |
| }, | |
| AccountActorMsg::Shutdown => { | |
| // Send message to ChainActor to cancel current transaction | |
| }, | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pub enum ChainActorMsg { | |
| ProcessTx { | |
| account: AccountOrigin, | |
| id: TransactionId, | |
| }, | |
| BlockNumberChanged(BlockNumber), | |
| } | |
| pub struct ChainActor { | |
| store: Arc<StoreClient>, | |
| chain_state: ChainState, | |
| block_num: BlockNumber, | |
| rt: tokio::runtime::Runtime, | |
| } | |
| impl ChainActor { | |
| pub fn on_message(&mut self, msg: ChainActorMsg, ctx: ActorContext) { | |
| match msg { | |
| ChainActorMsg::BlockNumberChanged(block_number) => { | |
| self.block_num = block_number; | |
| }, | |
| ChainActorMsg::ProcessTx { account } => { | |
| let store = Arc::clone(&self.store); | |
| let block_num = self.block_num; | |
| let mut chain_state = self.chain_state.clone(); | |
| // TODO Network accounts could be cached within the actor | |
| let account_data = self.rt.block_on(async move || match account { | |
| AccountOrigin::Store(prefix) => store | |
| .get_network_account(prefix) | |
| .await | |
| .expect("actor should be able to load account") | |
| .expect("actor account should exist"), | |
| AccountOrigin::Transaction(ref acc) => acc.clone(), | |
| }); | |
| let store_ref = Arc::clone(&self.store); | |
| let origin_prefix = account_data.prefix(); | |
| let mut state = self.rt.block_on(async move || { | |
| NetworkAccountState::load(account_data, origin_prefix, &store_ref, block_num) | |
| .expect("actor should be able to load account state") | |
| .await | |
| }); | |
| if let Some(tx_candidate) = | |
| state.select_candidate(crate::MAX_NOTES_PER_TX, chain_state) | |
| { | |
| self.rt.block_on(async move || { | |
| let tx_id = state.execute_transactions(tx_candidate).await; | |
| ctx.select::<AccountActor>(tx_candidate.account) | |
| .send(AccountActorMsg::TxCompleted(tx_id)); | |
| }); | |
| } | |
| }, | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment