Skip to main content

forest/message_pool/msgpool/
mod.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4pub(in crate::message_pool) mod events;
5pub(in crate::message_pool) mod metrics;
6pub(in crate::message_pool) mod msg_pool;
7pub(in crate::message_pool) mod msg_set;
8pub(in crate::message_pool) mod pending_store;
9pub(in crate::message_pool) mod provider;
10pub(in crate::message_pool) mod reorg;
11pub(in crate::message_pool) mod republish;
12pub mod selection;
13#[cfg(test)]
14pub mod test_provider;
15pub(in crate::message_pool) mod utils;
16
17pub use events::{MpoolSubscriber, MpoolUpdate};
18
19pub(in crate::message_pool) use utils::recover_sig;
20
21use crate::shim::percent::Percent;
22
23const REPLACE_BY_FEE_RATIO_MIN: Percent = Percent(110);
24const RBF_DENOM: u64 = 100;
25const BASE_FEE_LOWER_BOUND_FACTOR_CONSERVATIVE: i64 = 100;
26const MIN_GAS: u64 = 1298450;
27
28#[cfg(test)]
29pub mod tests {
30    use std::{borrow::BorrowMut, time::Duration};
31
32    use crate::blocks::Tipset;
33    use crate::key_management::{KeyStore, KeyStoreConfig, Wallet};
34    use crate::libp2p::NetworkMessage;
35    use crate::message::{MessageRead as _, SignedMessage};
36    use crate::networks::ChainConfig;
37    use crate::shim::{
38        address::Address,
39        crypto::{Signature, SignatureType},
40        econ::TokenAmount,
41        message::{Message, Message_v3},
42    };
43    use ahash::{HashMap, HashMapExt};
44    use num_traits::Zero;
45    use test_provider::*;
46    use tokio::task::JoinSet;
47
48    use super::*;
49    use crate::message_pool::{
50        Error,
51        msg_chain::{Chains, create_message_chains},
52        msg_pool::MessagePool,
53        provider::Provider,
54    };
55
56    struct TestMpool {
57        mpool: MessagePool<TestApi>,
58        wallet: Wallet,
59        sender: Address,
60        target: Address,
61        services: JoinSet<anyhow::Result<()>>,
62        network_rx: flume::Receiver<NetworkMessage>,
63    }
64
65    fn make_test_mpool(
66        tma: TestApi,
67    ) -> (
68        MessagePool<TestApi>,
69        JoinSet<anyhow::Result<()>>,
70        flume::Receiver<NetworkMessage>,
71    ) {
72        let (tx, rx) = flume::bounded(50);
73        let mut services = JoinSet::new();
74        let mpool = MessagePool::new(
75            tma,
76            tx,
77            Default::default(),
78            Default::default(),
79            &mut services,
80        )
81        .unwrap();
82        (mpool, services, rx)
83    }
84
85    fn make_test_setup() -> TestMpool {
86        let keystore = KeyStore::new(KeyStoreConfig::Memory).unwrap();
87        let mut wallet = Wallet::new(keystore);
88        let sender = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
89        let target = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
90        let tma = TestApi::default();
91        tma.set_state_sequence(&sender, 0);
92        let (mpool, services, network_rx) = make_test_mpool(tma);
93        TestMpool {
94            mpool,
95            wallet,
96            sender,
97            target,
98            services,
99            network_rx,
100        }
101    }
102
103    #[tokio::test]
104    async fn test_per_actor_limit() {
105        let keystore = KeyStore::new(KeyStoreConfig::Memory).unwrap();
106        let mut wallet = Wallet::new(keystore);
107        let sender = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
108        let target = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
109        let tma = TestApi::with_max_actor_pending_messages(200);
110        tma.set_state_sequence(&sender, 0);
111        let (mpool, _services, _rx) = make_test_mpool(tma);
112
113        let mut smsg_vec = Vec::new();
114        for i in 0..(mpool.api.max_actor_pending_messages() + 1) {
115            let msg = create_smsg(&target, &sender, wallet.borrow_mut(), i, 1000000, 1);
116            smsg_vec.push(msg);
117        }
118
119        let (last, body) = smsg_vec.split_last().unwrap();
120        for smsg in body {
121            mpool.add(smsg.clone()).await.unwrap();
122        }
123        assert_eq!(
124            mpool.add(last.clone()).await,
125            Err(Error::TooManyPendingMessages(sender.to_string(), true))
126        );
127    }
128
129    pub fn create_smsg(
130        to: &Address,
131        from: &Address,
132        wallet: &mut Wallet,
133        sequence: u64,
134        gas_limit: i64,
135        gas_price: u64,
136    ) -> SignedMessage {
137        let umsg: Message = Message_v3 {
138            to: to.into(),
139            from: from.into(),
140            sequence,
141            gas_limit: gas_limit as u64,
142            gas_fee_cap: TokenAmount::from_atto(gas_price + 100).into(),
143            gas_premium: TokenAmount::from_atto(gas_price).into(),
144            ..Message_v3::default()
145        }
146        .into();
147        let msg_signing_bytes = umsg.cid().to_bytes();
148        let sig = wallet.sign(from, msg_signing_bytes.as_slice()).unwrap();
149        SignedMessage::new_unchecked(umsg, sig)
150    }
151
152    // Create a fake signed message with a dummy signature. While the signature is
153    // not valid, it has been added to the validation cache and the message will
154    // appear authentic.
155    pub fn create_fake_smsg(
156        pool: &MessagePool<TestApi>,
157        to: &Address,
158        from: &Address,
159        sequence: u64,
160        gas_limit: i64,
161        gas_price: u64,
162    ) -> SignedMessage {
163        let umsg: Message = Message_v3 {
164            to: to.into(),
165            from: from.into(),
166            sequence,
167            gas_limit: gas_limit as u64,
168            gas_fee_cap: TokenAmount::from_atto(gas_price + 100).into(),
169            gas_premium: TokenAmount::from_atto(gas_price).into(),
170            ..Message_v3::default()
171        }
172        .into();
173        let sig = Signature::new_secp256k1(vec![]);
174        let signed = SignedMessage::new_unchecked(umsg, sig);
175        let cid = signed.cid();
176        pool.caches.sig_val.insert(cid.into(), ());
177        signed
178    }
179
180    #[tokio::test]
181    async fn test_message_pool() {
182        let TestMpool {
183            mpool,
184            mut wallet,
185            sender,
186            target,
187            ..
188        } = make_test_setup();
189
190        let mut smsg_vec = Vec::new();
191        for i in 0..2 {
192            let msg = create_smsg(&target, &sender, wallet.borrow_mut(), i, 1000000, 1);
193            smsg_vec.push(msg);
194        }
195
196        mpool.api.inner.lock().set_state_sequence(&sender, 0);
197        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 0);
198        mpool.add(smsg_vec[0].clone()).await.unwrap();
199        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 1);
200        mpool.add(smsg_vec[1].clone()).await.unwrap();
201        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 2);
202
203        let a = mock_block(1, 1);
204
205        mpool.api.inner.lock().set_block_messages(&a, smsg_vec);
206        mpool
207            .apply_head_change(Vec::new(), vec![Tipset::from(a)])
208            .await
209            .unwrap();
210
211        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 2);
212    }
213
214    #[tokio::test]
215    async fn test_revert_messages() {
216        let tma = TestApi::default();
217        let keystore = KeyStore::new(KeyStoreConfig::Memory).unwrap();
218        let mut wallet = Wallet::new(keystore);
219
220        let a = mock_block(1, 1);
221        let tipset = Tipset::from(&a);
222        let b = mock_block_with_parents(&tipset, 1, 1);
223
224        let sender = wallet.generate_addr(SignatureType::Bls).unwrap();
225        let target = Address::new_id(1001);
226
227        let mut smsg_vec = Vec::new();
228
229        for i in 0..4 {
230            let msg = create_smsg(&target, &sender, wallet.borrow_mut(), i, 1000000, 1);
231            smsg_vec.push(msg);
232        }
233        let (mpool, _services, _rx) = make_test_mpool(tma);
234
235        {
236            let mut api_temp = mpool.api.inner.lock();
237            api_temp.set_block_messages(&a, vec![smsg_vec[0].clone()]);
238            api_temp.set_block_messages(&b.clone(), smsg_vec[1..4].to_vec());
239            api_temp.set_state_sequence(&sender, 0);
240            drop(api_temp);
241        }
242
243        mpool.add(smsg_vec[0].clone()).await.unwrap();
244        mpool.add(smsg_vec[1].clone()).await.unwrap();
245        mpool.add(smsg_vec[2].clone()).await.unwrap();
246        mpool.add(smsg_vec[3].clone()).await.unwrap();
247
248        mpool.api.set_state_sequence(&sender, 0);
249
250        mpool
251            .apply_head_change(Vec::new(), vec![Tipset::from(a)])
252            .await
253            .unwrap();
254
255        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 4);
256
257        mpool.api.set_state_sequence(&sender, 1);
258
259        mpool
260            .apply_head_change(Vec::new(), vec![Tipset::from(&b)])
261            .await
262            .unwrap();
263
264        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 4);
265
266        mpool.api.set_state_sequence(&sender, 0);
267
268        mpool
269            .apply_head_change(vec![Tipset::from(b)], Vec::new())
270            .await
271            .unwrap();
272
273        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 4);
274
275        let (p, _) = mpool.pending();
276        assert_eq!(p.len(), 3);
277    }
278
279    #[tokio::test]
280    async fn test_get_sequence_resolves_id_address() {
281        let tma = TestApi::default();
282        let keystore = KeyStore::new(KeyStoreConfig::Memory).unwrap();
283        let mut wallet = Wallet::new(keystore);
284        let key_addr = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
285        let id_addr = Address::new_id(999);
286
287        tma.set_key_address_mapping(&id_addr, &key_addr);
288        tma.set_state_sequence(&key_addr, 0);
289        let (mpool, _services, _rx) = make_test_mpool(tma);
290
291        let target = Address::new_id(1001);
292        for i in 0..3 {
293            let msg = create_smsg(&target, &key_addr, wallet.borrow_mut(), i, 1000000, 1);
294            mpool.add(msg).await.unwrap();
295        }
296
297        // get_sequence with ID address should see the same pending messages
298        assert_eq!(mpool.get_sequence(&id_addr).await.unwrap(), 3);
299        assert_eq!(mpool.get_sequence(&key_addr).await.unwrap(), 3);
300    }
301
302    #[tokio::test]
303    async fn test_pending_for_resolves_id_address() {
304        let tma = TestApi::default();
305        let keystore = KeyStore::new(KeyStoreConfig::Memory).unwrap();
306        let mut wallet = Wallet::new(keystore);
307        let key_addr = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
308        let id_addr = Address::new_id(888);
309
310        tma.set_key_address_mapping(&id_addr, &key_addr);
311        tma.set_state_sequence(&key_addr, 0);
312        let (mpool, _services, _rx) = make_test_mpool(tma);
313
314        let target = Address::new_id(1001);
315        for i in 0..2 {
316            let msg = create_smsg(&target, &key_addr, wallet.borrow_mut(), i, 1000000, 1);
317            mpool.add(msg).await.unwrap();
318        }
319
320        // pending_for with ID address should find messages added under key address
321        let msgs = mpool
322            .pending_for(&id_addr)
323            .await
324            .expect("should find pending messages");
325        assert_eq!(msgs.len(), 2);
326
327        // pending_for with key address should also work
328        let msgs2 = mpool
329            .pending_for(&key_addr)
330            .await
331            .expect("should find pending messages");
332        assert_eq!(msgs2.len(), 2);
333    }
334
335    #[tokio::test]
336    async fn test_add_with_id_from_resolves_to_key_in_pending() {
337        let tma = TestApi::default();
338        let key_addr = Address::new_bls(&[11u8; 48]).unwrap();
339        let id_addr = Address::new_id(777);
340
341        tma.set_key_address_mapping(&id_addr, &key_addr);
342        tma.set_state_sequence(&key_addr, 0);
343        let (mpool, _services, _rx) = make_test_mpool(tma);
344
345        // Create a message with the ID address as sender and a fake signature
346        let msg = create_fake_smsg(&mpool, &Address::new_id(1001), &id_addr, 0, 1000000, 1);
347        mpool.add(msg).await.unwrap();
348
349        // Pending map should be keyed by key_addr, not id_addr.
350        assert!(
351            mpool.pending.snapshot_for(&key_addr).is_some(),
352            "pending should be keyed by resolved key address"
353        );
354        assert!(
355            mpool.pending.snapshot_for(&id_addr).is_none(),
356            "pending should NOT have entry under raw ID address"
357        );
358    }
359
360    #[tokio::test]
361    async fn test_head_change_removes_via_resolved_address() {
362        let tma = TestApi::default();
363        let keystore = KeyStore::new(KeyStoreConfig::Memory).unwrap();
364        let mut wallet = Wallet::new(keystore);
365        let key_addr = wallet.generate_addr(SignatureType::Bls).unwrap();
366        let id_addr = Address::new_id(555);
367
368        tma.set_key_address_mapping(&id_addr, &key_addr);
369        tma.set_state_sequence(&key_addr, 0);
370
371        let a = mock_block(1, 1);
372        let (mpool, _services, _rx) = make_test_mpool(tma);
373
374        let target = Address::new_id(1001);
375        let msg0 = create_smsg(&target, &key_addr, wallet.borrow_mut(), 0, 1000000, 1);
376        let msg1 = create_smsg(&target, &key_addr, wallet.borrow_mut(), 1, 1000000, 1);
377        mpool.add(msg0.clone()).await.unwrap();
378        mpool.add(msg1).await.unwrap();
379        assert_eq!(mpool.get_sequence(&key_addr).await.unwrap(), 2);
380
381        // Block messages are stored under the key_addr (as would appear on chain).
382        // The head_change remove path resolves addresses before touching pending.
383        mpool.api.inner.lock().set_block_messages(&a, vec![msg0]);
384
385        mpool.api.set_state_sequence(&key_addr, 1);
386
387        mpool
388            .apply_head_change(Vec::new(), vec![Tipset::from(a)])
389            .await
390            .unwrap();
391
392        // msg0 was applied on chain, msg1 remains pending
393        assert_eq!(mpool.get_sequence(&id_addr).await.unwrap(), 2);
394        let msgs = mpool
395            .pending_for(&key_addr)
396            .await
397            .expect("should have remaining msg");
398        assert_eq!(msgs.len(), 1);
399        assert_eq!(msgs[0].sequence(), 1);
400    }
401
402    #[tokio::test]
403    async fn test_async_message_pool() {
404        let TestMpool {
405            mpool,
406            mut wallet,
407            sender,
408            target,
409            services: _services,
410            network_rx: _network_rx,
411        } = make_test_setup();
412
413        let mut smsg_vec = Vec::new();
414        for i in 0..3 {
415            let msg = create_smsg(&target, &sender, wallet.borrow_mut(), i, 1000000, 1);
416            smsg_vec.push(msg);
417        }
418
419        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 0);
420        mpool.push(smsg_vec[0].clone()).await.unwrap();
421        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 1);
422        mpool.push(smsg_vec[1].clone()).await.unwrap();
423        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 2);
424        mpool.push(smsg_vec[2].clone()).await.unwrap();
425        assert_eq!(mpool.get_sequence(&sender).await.unwrap(), 3);
426
427        let header = mock_block(1, 1);
428        let tipset = Tipset::from(&header.clone());
429
430        mpool.api.set_heaviest_tipset(tipset.clone());
431
432        // sleep allows for async block to update mpool's cur_tipset
433        tokio::time::sleep(Duration::new(2, 0)).await;
434
435        let cur_ts = mpool.current_tipset();
436        assert_eq!(cur_ts, tipset);
437    }
438
439    #[tokio::test]
440    async fn test_msg_chains() {
441        let keystore = KeyStore::new(KeyStoreConfig::Memory).unwrap();
442        let mut wallet = Wallet::new(keystore);
443        let a1 = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
444        let a2 = wallet.generate_addr(SignatureType::Secp256k1).unwrap();
445        let tma = TestApi::default();
446        let gas_limit = 6955002;
447
448        let a = mock_block(1, 1);
449        let ts = Tipset::from(a);
450        let chain_config = ChainConfig::default();
451
452        // --- Test Chain Aggregations ---
453        // Test 1: 10 messages from a1 to a2, with increasing gasPerf; it should
454        // 	       make a single chain with 10 messages given enough balance
455        let mut mset = HashMap::new();
456        let mut smsg_vec = Vec::new();
457        for i in 0..10 {
458            let msg = create_smsg(&a2, &a1, wallet.borrow_mut(), i, gas_limit, 1 + i);
459            smsg_vec.push(msg.clone());
460            mset.insert(i, msg);
461        }
462
463        let mut chains = Chains::new();
464        create_message_chains(
465            &tma,
466            &a1,
467            &mset,
468            &TokenAmount::zero(),
469            &ts,
470            &mut chains,
471            &chain_config,
472        )
473        .unwrap();
474        assert_eq!(chains.len(), 1, "expected a single chain");
475        assert_eq!(
476            chains[0].msgs.len(),
477            10,
478            "expected 10 messages in single chain, got: {}",
479            chains[0].msgs.len()
480        );
481        for (i, m) in chains[0].msgs.iter().enumerate() {
482            assert_eq!(
483                m.sequence(),
484                i as u64,
485                "expected sequence {} but got {}",
486                i,
487                m.sequence()
488            );
489        }
490
491        // Test 2: 10 messages from a1 to a2, with decreasing gasPerf; it should
492        // 	         make 10 chains with 1 message each
493        let mut mset = HashMap::new();
494        let mut smsg_vec = Vec::new();
495        for i in 0..10 {
496            let msg = create_smsg(&a2, &a1, wallet.borrow_mut(), i, gas_limit, 10 - i);
497            smsg_vec.push(msg.clone());
498            mset.insert(i, msg);
499        }
500        let mut chains = Chains::new();
501        create_message_chains(
502            &tma,
503            &a1,
504            &mset,
505            &TokenAmount::zero(),
506            &ts,
507            &mut chains,
508            &chain_config,
509        )
510        .unwrap();
511        assert_eq!(chains.len(), 10, "expected 10 chains");
512
513        for i in 0..chains.len() {
514            assert_eq!(
515                chains[i].msgs.len(),
516                1,
517                "expected 1 message in chain {} but got {}",
518                i,
519                chains[i].msgs.len()
520            );
521        }
522
523        for i in 0..chains.len() {
524            let m = &chains[i].msgs[0];
525            assert_eq!(
526                m.sequence(),
527                i as u64,
528                "expected sequence {} but got {}",
529                i,
530                m.sequence()
531            );
532        }
533
534        // Test 3a: 10 messages from a1 to a2, with gasPerf increasing in groups of 3;
535        // it should          merge them in two chains, one with 9 messages and
536        // one with the last message
537        let mut mset = HashMap::new();
538        let mut smsg_vec = Vec::new();
539        for i in 0..10 {
540            let msg = create_smsg(&a2, &a1, wallet.borrow_mut(), i, gas_limit, 1 + i % 3);
541            smsg_vec.push(msg.clone());
542            mset.insert(i, msg);
543        }
544        let mut chains = Chains::new();
545        create_message_chains(
546            &tma,
547            &a1,
548            &mset,
549            &TokenAmount::zero(),
550            &ts,
551            &mut chains,
552            &chain_config,
553        )
554        .unwrap();
555        assert_eq!(chains.len(), 2, "expected 2 chains");
556        assert_eq!(chains[0].msgs.len(), 9);
557        assert_eq!(chains[1].msgs.len(), 1);
558        let mut next_nonce = 0;
559        for i in 0..chains.len() {
560            for m in chains[i].msgs.iter() {
561                assert_eq!(
562                    next_nonce,
563                    m.sequence(),
564                    "expected nonce {} but got {}",
565                    next_nonce,
566                    m.sequence()
567                );
568                next_nonce += 1;
569            }
570        }
571
572        // Test 3b: 10 messages from a1 to a2, with gasPerf decreasing in groups of 3
573        // with a bias for the          earlier chains; it should make 4 chains,
574        // the first 3 with 3 messages and the last with          a single
575        // message
576        let mut mset = HashMap::new();
577        let mut smsg_vec = Vec::new();
578        for i in 0..10 {
579            let bias = (12 - i) / 3;
580            let msg = create_smsg(
581                &a2,
582                &a1,
583                wallet.borrow_mut(),
584                i,
585                gas_limit,
586                1 + i % 3 + bias,
587            );
588            smsg_vec.push(msg.clone());
589            mset.insert(i, msg);
590        }
591
592        let mut chains = Chains::new();
593        create_message_chains(
594            &tma,
595            &a1,
596            &mset,
597            &TokenAmount::zero(),
598            &ts,
599            &mut chains,
600            &chain_config,
601        )
602        .unwrap();
603
604        for i in 0..chains.len() {
605            let expected_len = if i > 2 { 1 } else { 3 };
606            assert_eq!(
607                chains[i].msgs.len(),
608                expected_len,
609                "expected {} message in chain {} but got {}",
610                expected_len,
611                i,
612                chains[i].msgs.len()
613            );
614        }
615
616        let mut next_nonce = 0;
617        for i in 0..chains.len() {
618            for m in chains[i].msgs.iter() {
619                assert_eq!(
620                    next_nonce,
621                    m.sequence(),
622                    "expected nonce {} but got {}",
623                    next_nonce,
624                    m.sequence()
625                );
626                next_nonce += 1;
627            }
628        }
629
630        // --- Test Chain Breaks ---
631        // Test 4: 10 messages with non-consecutive nonces; it should make a single
632        // chain with just         the first message
633        let mut mset = HashMap::new();
634        let mut smsg_vec = Vec::new();
635        for i in 0..10 {
636            let msg = create_smsg(&a2, &a1, wallet.borrow_mut(), i * 2, gas_limit, 1 + i);
637            smsg_vec.push(msg.clone());
638            mset.insert(i, msg);
639        }
640
641        let mut chains = Chains::new();
642        create_message_chains(
643            &tma,
644            &a1,
645            &mset,
646            &TokenAmount::zero(),
647            &ts,
648            &mut chains,
649            &chain_config,
650        )
651        .unwrap();
652        assert_eq!(chains.len(), 1, "expected a single chain");
653        for (i, m) in chains[0].msgs.iter().enumerate() {
654            assert_eq!(
655                m.sequence(),
656                i as u64,
657                "expected nonce {} but got {}",
658                i,
659                m.sequence()
660            );
661        }
662
663        // Test 5: 10 messages with increasing gasLimit, except for the 6th message
664        // which has less than         the epoch gasLimit; it should create a
665        // single chain with the first 5 messages
666        let mut mset = HashMap::new();
667        let mut smsg_vec = Vec::new();
668        tma.set_state_balance_raw(&a1, TokenAmount::from_atto(1_000_000_000_000_000_000_u64));
669        for i in 0..10 {
670            let msg = if i != 5 {
671                create_smsg(&a2, &a1, wallet.borrow_mut(), i, gas_limit, 1 + i)
672            } else {
673                create_smsg(&a2, &a1, wallet.borrow_mut(), i, 1, 1 + i)
674            };
675            smsg_vec.push(msg.clone());
676            mset.insert(i, msg);
677        }
678        let mut chains = Chains::new();
679        create_message_chains(
680            &tma,
681            &a1,
682            &mset,
683            &TokenAmount::zero(),
684            &ts,
685            &mut chains,
686            &chain_config,
687        )
688        .unwrap();
689        assert_eq!(chains.len(), 1, "expected a single chain");
690        assert_eq!(chains[0].msgs.len(), 5);
691        for (i, m) in chains[0].msgs.iter().enumerate() {
692            assert_eq!(
693                m.sequence(),
694                i as u64,
695                "expected nonce {} but got {}",
696                i,
697                m.sequence()
698            );
699        }
700
701        // Test 6: one more message than what can fit in a block according to gas limit,
702        // with increasing         gasPerf; it should create a single chain with
703        // the max messages
704        let mut mset = HashMap::new();
705        let mut smsg_vec = Vec::new();
706        let max_messages = crate::shim::econ::BLOCK_GAS_LIMIT as i64 / gas_limit;
707        let n_messages = max_messages + 1;
708        for i in 0..n_messages {
709            let msg = create_smsg(
710                &a2,
711                &a1,
712                wallet.borrow_mut(),
713                i as u64,
714                gas_limit,
715                (1 + i) as u64,
716            );
717            smsg_vec.push(msg.clone());
718            mset.insert(i as u64, msg);
719        }
720        let mut chains = Chains::new();
721        create_message_chains(
722            &tma,
723            &a1,
724            &mset,
725            &TokenAmount::zero(),
726            &ts,
727            &mut chains,
728            &chain_config,
729        )
730        .unwrap();
731        assert_eq!(chains.len(), 1, "expected a single chain");
732        assert_eq!(chains[0].msgs.len(), max_messages as usize);
733        for (i, m) in chains[0].msgs.iter().enumerate() {
734            assert_eq!(
735                m.sequence(),
736                i as u64,
737                "expected nonce {} but got {}",
738                i,
739                m.sequence()
740            );
741        }
742
743        // Test 7: insufficient balance for all messages
744        tma.set_state_balance_raw(&a1, TokenAmount::from_atto(300 * gas_limit + 1));
745        let mut mset = HashMap::new();
746        let mut smsg_vec = Vec::new();
747        for i in 0..10 {
748            let msg = create_smsg(&a2, &a1, wallet.borrow_mut(), i, gas_limit, 1 + i);
749            smsg_vec.push(msg.clone());
750            mset.insert(i, msg);
751        }
752        let mut chains = Chains::new();
753        create_message_chains(
754            &tma,
755            &a1,
756            &mset,
757            &TokenAmount::zero(),
758            &ts,
759            &mut chains,
760            &chain_config,
761        )
762        .unwrap();
763        assert_eq!(chains.len(), 1, "expected a single chain");
764        assert_eq!(chains[0].msgs.len(), 2);
765        for (i, m) in chains[0].msgs.iter().enumerate() {
766            assert_eq!(
767                m.sequence(),
768                i as u64,
769                "expected nonce {} but got {}",
770                i,
771                m.sequence()
772            );
773        }
774    }
775}