@@ -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 ,
@@ -582,7 +582,7 @@ impl<R: Runtime> Dispatcher<R> {
582582 messages,
583583 block_tags,
584584 tx_reject_hashes : vec ! [ ] ,
585- in_msgs_count : 0 , // TODO: Support processing incoming messages.
585+ in_msgs_count : 0 ,
586586 } )
587587 } )
588588 }
@@ -593,17 +593,63 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
593593 & self ,
594594 rt_ctx : transaction:: Context < ' _ > ,
595595 batch : & TxnBatch ,
596- _in_msgs : & [ roothash:: IncomingMessage ] ,
596+ in_msgs : & [ roothash:: IncomingMessage ] ,
597597 ) -> Result < ExecuteBatchResult , RuntimeError > {
598- self . execute_batch_common (
598+ let mut in_msgs_count = 0 ;
599+
600+ let mut result = self . execute_batch_common (
599601 rt_ctx,
600602 |ctx| -> Result < Vec < ExecuteTxResult > , RuntimeError > {
601603 // If prefetch limit is set enable prefetch.
602604 let prefetch_enabled = R :: PREFETCH_LIMIT > 0 ;
605+ let mut results = Vec :: with_capacity ( batch. len ( ) ) ;
606+
607+ // Process incoming messages first.
608+ let mut batch_it = batch. iter ( ) ;
609+ ' inmsg: for in_msg in in_msgs {
610+ match R :: IncomingMessagesHandler :: process_in_msg ( ctx, & in_msg) {
611+ InMsgResult :: Skip => {
612+ // Skip, but treat as processed.
613+ in_msgs_count += 1 ;
614+ }
615+ InMsgResult :: Execute ( raw_tx, tx) => {
616+ // Verify that the transaction has been included in the batch.
617+ match batch_it. next ( ) {
618+ None => {
619+ // Nothing in the batch when there should be an incoming message.
620+ return Err ( Error :: MalformedTransactionInBatch ( anyhow ! (
621+ "missing incoming message"
622+ ) )
623+ . into ( ) ) ;
624+ }
625+ Some ( batch_tx) if batch_tx != raw_tx => {
626+ // Incoming message does not match what is in the batch.
627+ return Err ( Error :: MalformedTransactionInBatch ( anyhow ! (
628+ "mismatched incoming message"
629+ ) )
630+ . into ( ) ) ;
631+ }
632+ _ => {
633+ // Everything is ok.
634+ }
635+ }
636+
637+ // Further execute the inner transaction. The transaction has already
638+ // passed checks so it is ok to include in a block.
639+ let tx_size = raw_tx. len ( ) . try_into ( ) . unwrap ( ) ;
640+ let index = results. len ( ) ;
641+ results. push ( Self :: execute_tx ( ctx, tx_size, tx, index) ?) ;
642+
643+ in_msgs_count += 1 ;
644+ }
645+ InMsgResult :: Stop => break ' inmsg,
646+ }
647+ }
603648
649+ let inmsg_txs = results. len ( ) ;
604650 let mut txs = Vec :: with_capacity ( batch. len ( ) ) ;
605651 let mut prefixes: BTreeSet < Prefix > = BTreeSet :: new ( ) ;
606- for tx in batch. iter ( ) {
652+ for tx in batch. iter ( ) . skip ( inmsg_txs ) {
607653 let tx_size = tx. len ( ) . try_into ( ) . map_err ( |_| {
608654 Error :: MalformedTransactionInBatch ( anyhow ! ( "transaction too large" ) )
609655 } ) ?;
@@ -629,23 +675,29 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
629675
630676 // Execute the batch.
631677 let mut results = Vec :: with_capacity ( batch. len ( ) ) ;
632- for ( index, ( tx_size, tx_hash, tx) ) in txs. into_iter ( ) . enumerate ( ) {
678+ for ( index, ( tx_size, tx_hash, tx) ) in txs. into_iter ( ) . skip ( inmsg_txs ) . enumerate ( ) {
633679 results. push ( Self :: execute_tx ( ctx, tx_size, tx_hash, tx, index) ?) ;
634680 }
635681
636682 Ok ( results)
637683 } ,
638- )
684+ ) ?;
685+
686+ // Include number of processed incoming messages in the final result.
687+ result. in_msgs_count = in_msgs_count;
688+
689+ Ok ( result)
639690 }
640691
641692 fn schedule_and_execute_batch (
642693 & self ,
643694 rt_ctx : transaction:: Context < ' _ > ,
644695 batch : & mut TxnBatch ,
645- _in_msgs : & [ roothash:: IncomingMessage ] ,
696+ in_msgs : & [ roothash:: IncomingMessage ] ,
646697 ) -> Result < ExecuteBatchResult , RuntimeError > {
647698 let cfg = R :: SCHEDULE_CONTROL ;
648699 let mut tx_reject_hashes = Vec :: new ( ) ;
700+ let mut in_msgs_count = 0 ;
649701
650702 let mut result = self . execute_batch_common (
651703 rt_ctx,
@@ -655,13 +707,35 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
655707 // The idea is to keep scheduling transactions as long as we have some space
656708 // available in the block as determined by gas use.
657709 let mut new_batch = Vec :: new ( ) ;
658- let mut results = Vec :: with_capacity ( batch. len ( ) ) ;
710+ let mut results = Vec :: with_capacity ( in_msgs . len ( ) + batch. len ( ) ) ;
659711 let mut requested_batch_len = cfg. initial_batch_size ;
712+
713+ // Process incoming messages first.
714+ ' inmsg: for in_msg in in_msgs {
715+ match R :: IncomingMessagesHandler :: process_in_msg ( ctx, & in_msg) {
716+ InMsgResult :: Skip => {
717+ // Skip, but treat as processed.
718+ in_msgs_count += 1 ;
719+ }
720+ InMsgResult :: Execute ( raw_tx, tx) => {
721+ // Further execute the inner transaction. The transaction has already
722+ // passed checks so it is ok to include in a block.
723+ let tx_size = raw_tx. len ( ) . try_into ( ) . unwrap ( ) ;
724+ let index = new_batch. len ( ) ;
725+ new_batch. push ( raw_tx. to_owned ( ) ) ;
726+ results. push ( Self :: execute_tx ( ctx, tx_size, tx, index) ?) ;
727+
728+ in_msgs_count += 1 ;
729+ }
730+ InMsgResult :: Stop => break ' inmsg,
731+ }
732+ }
733+
734+ // Process regular transactions.
660735 ' batch: loop {
661736 // Remember length of last batch.
662737 let last_batch_len = batch. len ( ) ;
663738 let last_batch_tx_hash = batch. last ( ) . map ( |raw_tx| Hash :: digest_bytes ( raw_tx) ) ;
664-
665739 for raw_tx in batch. drain ( ..) {
666740 // If we don't have enough gas for processing even the cheapest transaction
667741 // we are done. Same if we reached the runtime-imposed maximum tx count.
@@ -774,8 +848,10 @@ impl<R: Runtime + Send + Sync> transaction::dispatcher::Dispatcher for Dispatche
774848 } ,
775849 ) ?;
776850
777- // Include rejected transaction hashes in the final result.
851+ // Include rejected transaction hashes and number of processed incoming messages in the
852+ // final result.
778853 result. tx_reject_hashes = tx_reject_hashes;
854+ result. in_msgs_count = in_msgs_count;
779855
780856 Ok ( result)
781857 }
@@ -1000,6 +1076,7 @@ mod test {
10001076 core:: Genesis {
10011077 parameters : core:: Parameters {
10021078 max_batch_gas : u64:: MAX ,
1079+ max_inmsg_gas : 0 ,
10031080 max_tx_size : 32 * 1024 ,
10041081 max_tx_signers : 1 ,
10051082 max_multisig_signers : 8 ,
0 commit comments