@@ -31,7 +31,7 @@ use crate::{
3131 error:: { Error as _, RuntimeError } ,
3232 event:: IntoTags ,
3333 keymanager:: { KeyManagerClient , KeyManagerError } ,
34- module:: { self , BlockHandler , MethodHandler , TransactionHandler } ,
34+ module:: { self , BlockHandler , InMsgHandler , InMsgResult , MethodHandler , TransactionHandler } ,
3535 modules,
3636 modules:: core:: API as _,
3737 runtime:: Runtime ,
@@ -537,7 +537,7 @@ impl<R: Runtime> Dispatcher<R> {
537537 messages,
538538 block_tags : block_tags. into_tags ( ) ,
539539 tx_reject_hashes : vec ! [ ] ,
540- in_msgs_count : 0 , // TODO: Support processing incoming messages.
540+ in_msgs_count : 0 ,
541541 } )
542542 }
543543}
@@ -547,17 +547,63 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
547547 & self ,
548548 rt_ctx : transaction:: Context < ' _ > ,
549549 batch : & TxnBatch ,
550- _in_msgs : & [ roothash:: IncomingMessage ] ,
550+ in_msgs : & [ roothash:: IncomingMessage ] ,
551551 ) -> Result < ExecuteBatchResult , RuntimeError > {
552- self . execute_batch_common (
552+ let mut in_msgs_count = 0 ;
553+
554+ let mut result = self . execute_batch_common (
553555 rt_ctx,
554556 |ctx| -> Result < Vec < ExecuteTxResult > , RuntimeError > {
555557 // If prefetch limit is set enable prefetch.
556558 let prefetch_enabled = R :: PREFETCH_LIMIT > 0 ;
559+ let mut results = Vec :: with_capacity ( batch. len ( ) ) ;
560+
561+ // Process incoming messages first.
562+ let mut batch_it = batch. iter ( ) ;
563+ ' inmsg: for in_msg in in_msgs {
564+ match R :: IncomingMessagesHandler :: process_in_msg ( ctx, & in_msg) {
565+ InMsgResult :: Skip => {
566+ // Skip, but treat as processed.
567+ in_msgs_count += 1 ;
568+ }
569+ InMsgResult :: Execute ( raw_tx, tx) => {
570+ // Verify that the transaction has been included in the batch.
571+ match batch_it. next ( ) {
572+ None => {
573+ // Nothing in the batch when there should be an incoming message.
574+ return Err ( Error :: MalformedTransactionInBatch ( anyhow ! (
575+ "missing incoming message"
576+ ) )
577+ . into ( ) ) ;
578+ }
579+ Some ( batch_tx) if batch_tx != raw_tx => {
580+ // Incoming message does not match what is in the batch.
581+ return Err ( Error :: MalformedTransactionInBatch ( anyhow ! (
582+ "mismatched incoming message"
583+ ) )
584+ . into ( ) ) ;
585+ }
586+ _ => {
587+ // Everything is ok.
588+ }
589+ }
590+
591+ // Further execute the inner transaction. The transaction has already
592+ // passed checks so it is ok to include in a block.
593+ let tx_size = raw_tx. len ( ) . try_into ( ) . unwrap ( ) ;
594+ let index = results. len ( ) ;
595+ results. push ( Self :: execute_tx ( ctx, tx_size, tx, index) ?) ;
557596
597+ in_msgs_count += 1 ;
598+ }
599+ InMsgResult :: Stop => break ' inmsg,
600+ }
601+ }
602+
603+ let inmsg_txs = results. len ( ) ;
558604 let mut txs = Vec :: with_capacity ( batch. len ( ) ) ;
559605 let mut prefixes: BTreeSet < Prefix > = BTreeSet :: new ( ) ;
560- for tx in batch. iter ( ) {
606+ for tx in batch. iter ( ) . skip ( inmsg_txs ) {
561607 let tx_size = tx. len ( ) . try_into ( ) . map_err ( |_| {
562608 Error :: MalformedTransactionInBatch ( anyhow ! ( "transaction too large" ) )
563609 } ) ?;
@@ -580,24 +626,29 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
580626 }
581627
582628 // Execute the batch.
583- let mut results = Vec :: with_capacity ( batch. len ( ) ) ;
584- for ( index, ( tx_size, tx) ) in txs. into_iter ( ) . enumerate ( ) {
629+ for ( index, ( tx_size, tx) ) in txs. into_iter ( ) . skip ( inmsg_txs) . enumerate ( ) {
585630 results. push ( Self :: execute_tx ( ctx, tx_size, tx, index) ?) ;
586631 }
587632
588633 Ok ( results)
589634 } ,
590- )
635+ ) ?;
636+
637+ // Include number of processed incoming messages in the final result.
638+ result. in_msgs_count = in_msgs_count;
639+
640+ Ok ( result)
591641 }
592642
593643 fn schedule_and_execute_batch (
594644 & self ,
595645 rt_ctx : transaction:: Context < ' _ > ,
596646 batch : & mut TxnBatch ,
597- _in_msgs : & [ roothash:: IncomingMessage ] ,
647+ in_msgs : & [ roothash:: IncomingMessage ] ,
598648 ) -> Result < ExecuteBatchResult , RuntimeError > {
599649 let cfg = R :: SCHEDULE_CONTROL ;
600650 let mut tx_reject_hashes = Vec :: new ( ) ;
651+ let mut in_msgs_count = 0 ;
601652
602653 let mut result = self . execute_batch_common (
603654 rt_ctx,
@@ -607,13 +658,35 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
607658 // The idea is to keep scheduling transactions as long as we have some space
608659 // available in the block as determined by gas use.
609660 let mut new_batch = Vec :: new ( ) ;
610- let mut results = Vec :: with_capacity ( batch. len ( ) ) ;
661+ let mut results = Vec :: with_capacity ( in_msgs . len ( ) + batch. len ( ) ) ;
611662 let mut requested_batch_len = cfg. initial_batch_size ;
663+
664+ // Process incoming messages first.
665+ ' inmsg: for in_msg in in_msgs {
666+ match R :: IncomingMessagesHandler :: process_in_msg ( ctx, & in_msg) {
667+ InMsgResult :: Skip => {
668+ // Skip, but treat as processed.
669+ in_msgs_count += 1 ;
670+ }
671+ InMsgResult :: Execute ( raw_tx, tx) => {
672+ // Further execute the inner transaction. The transaction has already
673+ // passed checks so it is ok to include in a block.
674+ let tx_size = raw_tx. len ( ) . try_into ( ) . unwrap ( ) ;
675+ let index = new_batch. len ( ) ;
676+ new_batch. push ( raw_tx. to_owned ( ) ) ;
677+ results. push ( Self :: execute_tx ( ctx, tx_size, tx, index) ?) ;
678+
679+ in_msgs_count += 1 ;
680+ }
681+ InMsgResult :: Stop => break ' inmsg,
682+ }
683+ }
684+
685+ // Process regular transactions.
612686 ' batch: loop {
613687 // Remember length of last batch.
614688 let last_batch_len = batch. len ( ) ;
615689 let last_batch_tx_hash = batch. last ( ) . map ( |raw_tx| Hash :: digest_bytes ( raw_tx) ) ;
616-
617690 for raw_tx in batch. drain ( ..) {
618691 // If we don't have enough gas for processing even the cheapest transaction
619692 // we are done. Same if we reached the runtime-imposed maximum tx count.
@@ -689,8 +762,10 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
689762 } ,
690763 ) ?;
691764
692- // Include rejected transaction hashes in the final result.
765+ // Include rejected transaction hashes and number of processed incoming messages in the
766+ // final result.
693767 result. tx_reject_hashes = tx_reject_hashes;
768+ result. in_msgs_count = in_msgs_count;
694769
695770 Ok ( result)
696771 }
@@ -877,6 +952,7 @@ mod test {
877952 core:: Genesis {
878953 parameters : core:: Parameters {
879954 max_batch_gas : u64:: MAX ,
955+ max_inmsg_gas : 0 ,
880956 max_tx_size : 32 * 1024 ,
881957 max_tx_signers : 1 ,
882958 max_multisig_signers : 8 ,
@@ -885,6 +961,7 @@ mod test {
885961 auth_signature : 0 ,
886962 auth_multisig_signer : 0 ,
887963 callformat_x25519_deoxysii : 0 ,
964+ inmsg_base : 0 ,
888965 } ,
889966 min_gas_price : BTreeMap :: from ( [ ( token:: Denomination :: NATIVE , 0 ) ] ) ,
890967 } ,
0 commit comments