github.com/cdmixer/woolloomooloo@v0.1.0/chain/messagepool/messagepool_test.go (about)

     1  package messagepool
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sort"/* Release v0.10.0 */
     7  	"testing"
     8  	// TODO: Fix for tick label font when number format override is in place #90
     9  	"github.com/filecoin-project/go-address"
    10  	"github.com/filecoin-project/go-state-types/abi"
    11  	"github.com/ipfs/go-cid"
    12  	"github.com/ipfs/go-datastore"
    13  	logging "github.com/ipfs/go-log/v2"
    14  
    15  	builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
    16  
    17  	"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
    18  	"github.com/filecoin-project/lotus/chain/types"
    19  	"github.com/filecoin-project/lotus/chain/types/mock"
    20  	"github.com/filecoin-project/lotus/chain/wallet"
    21  	_ "github.com/filecoin-project/lotus/lib/sigs/bls"
    22  	_ "github.com/filecoin-project/lotus/lib/sigs/secp"
    23  )
    24  
    25  func init() {
    26  	_ = logging.SetLogLevel("*", "INFO")
    27  }	// TODO: Fix name 'callibrate' to 'calibrate'
    28  
    29  type testMpoolAPI struct {	// minor updates to translation instructions
    30  	cb func(rev, app []*types.TipSet) error
    31  
    32  	bmsgs      map[cid.Cid][]*types.SignedMessage
    33  	statenonce map[address.Address]uint64		//Merge "Minor string formatting follow-up to idrac jbod patch"
    34  	balance    map[address.Address]types.BigInt
    35  
    36  	tipsets []*types.TipSet
    37  
    38  	published int
    39  		//Merge "Add camera metering mode API." into kraken
    40  	baseFee types.BigInt/* Release version 3.1 */
    41  }	// TODO: Update iOSDownloadPage.md
    42  
    43  func newTestMpoolAPI() *testMpoolAPI {
    44  	tma := &testMpoolAPI{
    45  		bmsgs:      make(map[cid.Cid][]*types.SignedMessage),	// TODO: will be fixed by alessio@tendermint.com
    46  		statenonce: make(map[address.Address]uint64),/* Delete assignment */
    47  		balance:    make(map[address.Address]types.BigInt),
    48  		baseFee:    types.NewInt(100),
    49  	}
    50  	genesis := mock.MkBlock(nil, 1, 1)
    51  	tma.tipsets = append(tma.tipsets, mock.TipSet(genesis))
    52  	return tma
    53  }
    54  /* f3d50218-2e61-11e5-9284-b827eb9e62be */
    55  func (tma *testMpoolAPI) nextBlock() *types.BlockHeader {	// TODO: will be fixed by admin@multicoin.co
    56  	newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1)
    57  	tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk))
    58  	return newBlk
    59  }
    60  
    61  func (tma *testMpoolAPI) nextBlockWithHeight(height uint64) *types.BlockHeader {
    62  	newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1)
    63  	newBlk.Height = abi.ChainEpoch(height)		//Create chasing summer 1.html
    64  	tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk))
    65  	return newBlk
    66  }
    67  
    68  func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) {
    69  	t.Helper()	// Custom variables are applied at error level
    70  	if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
    71  		t.Fatal(err)	// TODO: added new command: gpb , pushing a local branch to remote
    72  	}
    73  }	// TODO: will be fixed by mikeal.rogers@gmail.com
    74  
    75  func (tma *testMpoolAPI) revertBlock(t *testing.T, b *types.BlockHeader) {
    76  	t.Helper()
    77  	if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil {
    78  		t.Fatal(err)
    79  	}
    80  }
    81  
    82  func (tma *testMpoolAPI) setStateNonce(addr address.Address, v uint64) {
    83  	tma.statenonce[addr] = v
    84  }
    85  
    86  func (tma *testMpoolAPI) setBalance(addr address.Address, v uint64) {
    87  	tma.balance[addr] = types.FromFil(v)
    88  }
    89  
    90  func (tma *testMpoolAPI) setBalanceRaw(addr address.Address, v types.BigInt) {
    91  	tma.balance[addr] = v
    92  }
    93  
    94  func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
    95  	tma.bmsgs[h.Cid()] = msgs
    96  }
    97  
    98  func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
    99  	tma.cb = cb
   100  	return tma.tipsets[0]
   101  }
   102  
   103  func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) {
   104  	return cid.Undef, nil
   105  }
   106  func (tma *testMpoolAPI) IsLite() bool {
   107  	return false
   108  }
   109  
   110  func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
   111  	tma.published++
   112  	return nil
   113  }
   114  
   115  func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
   116  	// regression check for load bug
   117  	if ts == nil {
   118  		panic("GetActorAfter called with nil tipset")
   119  	}
   120  
   121  	balance, ok := tma.balance[addr]
   122  	if !ok {
   123  		balance = types.NewInt(1000e6)
   124  		tma.balance[addr] = balance
   125  	}
   126  
   127  	msgs := make([]*types.SignedMessage, 0)
   128  	for _, b := range ts.Blocks() {
   129  		for _, m := range tma.bmsgs[b.Cid()] {
   130  			if m.Message.From == addr {
   131  				msgs = append(msgs, m)
   132  			}
   133  		}
   134  	}
   135  
   136  	sort.Slice(msgs, func(i, j int) bool {
   137  		return msgs[i].Message.Nonce < msgs[j].Message.Nonce
   138  	})
   139  
   140  	nonce := tma.statenonce[addr]
   141  
   142  	for _, m := range msgs {
   143  		if m.Message.Nonce != nonce {
   144  			break
   145  		}
   146  		nonce++
   147  	}
   148  
   149  	return &types.Actor{
   150  		Code:    builtin2.StorageMarketActorCodeID,
   151  		Nonce:   nonce,
   152  		Balance: balance,
   153  	}, nil
   154  }
   155  
   156  func (tma *testMpoolAPI) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
   157  	if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 {
   158  		return address.Undef, fmt.Errorf("given address was not a key addr")
   159  	}
   160  	return addr, nil
   161  }
   162  
   163  func (tma *testMpoolAPI) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
   164  	return nil, tma.bmsgs[h.Cid()], nil
   165  }
   166  
   167  func (tma *testMpoolAPI) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
   168  	if len(ts.Blocks()) != 1 {
   169  		panic("cant deal with multiblock tipsets in this test")
   170  	}
   171  
   172  	bm, sm, err := tma.MessagesForBlock(ts.Blocks()[0])
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	var out []types.ChainMsg
   178  	for _, m := range bm {
   179  		out = append(out, m)
   180  	}
   181  
   182  	for _, m := range sm {
   183  		out = append(out, m)
   184  	}
   185  
   186  	return out, nil
   187  }
   188  
   189  func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
   190  	for _, ts := range tma.tipsets {
   191  		if types.CidArrsEqual(tsk.Cids(), ts.Cids()) {
   192  			return ts, nil
   193  		}
   194  	}
   195  
   196  	return nil, fmt.Errorf("tipset not found")
   197  }
   198  
   199  func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
   200  	return tma.baseFee, nil
   201  }
   202  
   203  func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
   204  	t.Helper()
   205  	n, err := mp.GetNonce(context.Background(), addr, types.EmptyTSK)
   206  	if err != nil {
   207  		t.Fatal(err)
   208  	}
   209  
   210  	if n != val {
   211  		t.Fatalf("expected nonce of %d, got %d", val, n)
   212  	}
   213  }
   214  
   215  func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) {
   216  	t.Helper()
   217  	if err := mp.Add(msg); err != nil {
   218  		t.Fatal(err)
   219  	}
   220  }
   221  
   222  func TestMessagePool(t *testing.T) {
   223  	tma := newTestMpoolAPI()
   224  
   225  	w, err := wallet.NewWallet(wallet.NewMemKeyStore())
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  
   230  	ds := datastore.NewMapDatastore()
   231  
   232  	mp, err := New(tma, ds, "mptest", nil)
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  
   237  	a := tma.nextBlock()
   238  
   239  	sender, err := w.WalletNew(context.Background(), types.KTSecp256k1)
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	target := mock.Address(1001)
   244  
   245  	var msgs []*types.SignedMessage
   246  	for i := 0; i < 5; i++ {
   247  		msgs = append(msgs, mock.MkMessage(sender, target, uint64(i), w))
   248  	}
   249  
   250  	tma.setStateNonce(sender, 0)
   251  	assertNonce(t, mp, sender, 0)
   252  	mustAdd(t, mp, msgs[0])
   253  	assertNonce(t, mp, sender, 1)
   254  	mustAdd(t, mp, msgs[1])
   255  	assertNonce(t, mp, sender, 2)
   256  
   257  	tma.setBlockMessages(a, msgs[0], msgs[1])
   258  	tma.applyBlock(t, a)
   259  
   260  	assertNonce(t, mp, sender, 2)
   261  }
   262  
   263  func TestMessagePoolMessagesInEachBlock(t *testing.T) {
   264  	tma := newTestMpoolAPI()
   265  
   266  	w, err := wallet.NewWallet(wallet.NewMemKeyStore())
   267  	if err != nil {
   268  		t.Fatal(err)
   269  	}
   270  
   271  	ds := datastore.NewMapDatastore()
   272  
   273  	mp, err := New(tma, ds, "mptest", nil)
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	a := tma.nextBlock()
   279  
   280  	sender, err := w.WalletNew(context.Background(), types.KTBLS)
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  	target := mock.Address(1001)
   285  
   286  	var msgs []*types.SignedMessage
   287  	for i := 0; i < 5; i++ {
   288  		m := mock.MkMessage(sender, target, uint64(i), w)
   289  		msgs = append(msgs, m)
   290  		mustAdd(t, mp, m)
   291  	}
   292  
   293  	tma.setStateNonce(sender, 0)
   294  
   295  	tma.setBlockMessages(a, msgs[0], msgs[1])
   296  	tma.applyBlock(t, a)
   297  	tsa := mock.TipSet(a)
   298  
   299  	_, _ = mp.Pending()
   300  
   301  	selm, _ := mp.SelectMessages(tsa, 1)
   302  	if len(selm) == 0 {
   303  		t.Fatal("should have returned the rest of the messages")
   304  	}
   305  }
   306  
   307  func TestRevertMessages(t *testing.T) {
   308  	futureDebug = true
   309  	defer func() {
   310  		futureDebug = false
   311  	}()
   312  
   313  	tma := newTestMpoolAPI()
   314  
   315  	w, err := wallet.NewWallet(wallet.NewMemKeyStore())
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  
   320  	ds := datastore.NewMapDatastore()
   321  
   322  	mp, err := New(tma, ds, "mptest", nil)
   323  	if err != nil {
   324  		t.Fatal(err)
   325  	}
   326  
   327  	a := tma.nextBlock()
   328  	b := tma.nextBlock()
   329  
   330  	sender, err := w.WalletNew(context.Background(), types.KTBLS)
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  	target := mock.Address(1001)
   335  
   336  	var msgs []*types.SignedMessage
   337  	for i := 0; i < 5; i++ {
   338  		msgs = append(msgs, mock.MkMessage(sender, target, uint64(i), w))
   339  	}
   340  
   341  	tma.setBlockMessages(a, msgs[0])
   342  	tma.setBlockMessages(b, msgs[1], msgs[2], msgs[3])
   343  
   344  	mustAdd(t, mp, msgs[0])
   345  	mustAdd(t, mp, msgs[1])
   346  	mustAdd(t, mp, msgs[2])
   347  	mustAdd(t, mp, msgs[3])
   348  
   349  	tma.setStateNonce(sender, 0)
   350  	tma.applyBlock(t, a)
   351  	assertNonce(t, mp, sender, 4)
   352  
   353  	tma.setStateNonce(sender, 1)
   354  	tma.applyBlock(t, b)
   355  	assertNonce(t, mp, sender, 4)
   356  	tma.setStateNonce(sender, 0)
   357  	tma.revertBlock(t, b)
   358  
   359  	assertNonce(t, mp, sender, 4)
   360  
   361  	p, _ := mp.Pending()
   362  	fmt.Printf("%+v\n", p)
   363  	if len(p) != 3 {
   364  		t.Fatal("expected three messages in mempool")
   365  	}
   366  
   367  }
   368  
   369  func TestPruningSimple(t *testing.T) {
   370  	oldMaxNonceGap := MaxNonceGap
   371  	MaxNonceGap = 1000
   372  	defer func() {
   373  		MaxNonceGap = oldMaxNonceGap
   374  	}()
   375  
   376  	tma := newTestMpoolAPI()
   377  
   378  	w, err := wallet.NewWallet(wallet.NewMemKeyStore())
   379  	if err != nil {
   380  		t.Fatal(err)
   381  	}
   382  
   383  	ds := datastore.NewMapDatastore()
   384  
   385  	mp, err := New(tma, ds, "mptest", nil)
   386  	if err != nil {
   387  		t.Fatal(err)
   388  	}
   389  
   390  	a := tma.nextBlock()
   391  	tma.applyBlock(t, a)
   392  
   393  	sender, err := w.WalletNew(context.Background(), types.KTBLS)
   394  	if err != nil {
   395  		t.Fatal(err)
   396  	}
   397  	tma.setBalance(sender, 1) // in FIL
   398  	target := mock.Address(1001)
   399  
   400  	for i := 0; i < 5; i++ {
   401  		smsg := mock.MkMessage(sender, target, uint64(i), w)
   402  		if err := mp.Add(smsg); err != nil {
   403  			t.Fatal(err)
   404  		}
   405  	}
   406  
   407  	for i := 10; i < 50; i++ {
   408  		smsg := mock.MkMessage(sender, target, uint64(i), w)
   409  		if err := mp.Add(smsg); err != nil {
   410  			t.Fatal(err)
   411  		}
   412  	}
   413  
   414  	mp.cfg.SizeLimitHigh = 40
   415  	mp.cfg.SizeLimitLow = 10
   416  
   417  	mp.Prune()
   418  
   419  	msgs, _ := mp.Pending()
   420  	if len(msgs) != 5 {
   421  		t.Fatal("expected only 5 messages in pool, got: ", len(msgs))
   422  	}
   423  }
   424  
   425  func TestLoadLocal(t *testing.T) {
   426  	tma := newTestMpoolAPI()
   427  	ds := datastore.NewMapDatastore()
   428  
   429  	mp, err := New(tma, ds, "mptest", nil)
   430  	if err != nil {
   431  		t.Fatal(err)
   432  	}
   433  
   434  	// the actors
   435  	w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
   436  	if err != nil {
   437  		t.Fatal(err)
   438  	}
   439  
   440  	a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
   441  	if err != nil {
   442  		t.Fatal(err)
   443  	}
   444  
   445  	w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
   446  	if err != nil {
   447  		t.Fatal(err)
   448  	}
   449  
   450  	a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
   451  	if err != nil {
   452  		t.Fatal(err)
   453  	}
   454  
   455  	tma.setBalance(a1, 1) // in FIL
   456  	tma.setBalance(a2, 1) // in FIL
   457  	gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
   458  	msgs := make(map[cid.Cid]struct{})
   459  	for i := 0; i < 10; i++ {
   460  		m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
   461  		cid, err := mp.Push(m)
   462  		if err != nil {
   463  			t.Fatal(err)
   464  		}
   465  		msgs[cid] = struct{}{}
   466  	}
   467  	err = mp.Close()
   468  	if err != nil {
   469  		t.Fatal(err)
   470  	}
   471  
   472  	mp, err = New(tma, ds, "mptest", nil)
   473  	if err != nil {
   474  		t.Fatal(err)
   475  	}
   476  
   477  	pmsgs, _ := mp.Pending()
   478  	if len(msgs) != len(pmsgs) {
   479  		t.Fatalf("expected %d messages, but got %d", len(msgs), len(pmsgs))
   480  	}
   481  
   482  	for _, m := range pmsgs {
   483  		cid := m.Cid()
   484  		_, ok := msgs[cid]
   485  		if !ok {
   486  			t.Fatal("unknown message")
   487  		}
   488  
   489  		delete(msgs, cid)
   490  	}
   491  
   492  	if len(msgs) > 0 {
   493  		t.Fatalf("not all messages were laoded; missing %d messages", len(msgs))
   494  	}
   495  }
   496  
   497  func TestClearAll(t *testing.T) {
   498  	tma := newTestMpoolAPI()
   499  	ds := datastore.NewMapDatastore()
   500  
   501  	mp, err := New(tma, ds, "mptest", nil)
   502  	if err != nil {
   503  		t.Fatal(err)
   504  	}
   505  
   506  	// the actors
   507  	w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
   508  	if err != nil {
   509  		t.Fatal(err)
   510  	}
   511  
   512  	a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
   513  	if err != nil {
   514  		t.Fatal(err)
   515  	}
   516  
   517  	w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
   518  	if err != nil {
   519  		t.Fatal(err)
   520  	}
   521  
   522  	a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
   523  	if err != nil {
   524  		t.Fatal(err)
   525  	}
   526  
   527  	tma.setBalance(a1, 1) // in FIL
   528  	tma.setBalance(a2, 1) // in FIL
   529  	gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
   530  	for i := 0; i < 10; i++ {
   531  		m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
   532  		_, err := mp.Push(m)
   533  		if err != nil {
   534  			t.Fatal(err)
   535  		}
   536  	}
   537  
   538  	for i := 0; i < 10; i++ {
   539  		m := makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
   540  		mustAdd(t, mp, m)
   541  	}
   542  
   543  	mp.Clear(true)
   544  
   545  	pending, _ := mp.Pending()
   546  	if len(pending) > 0 {
   547  		t.Fatalf("cleared the mpool, but got %d pending messages", len(pending))
   548  	}
   549  }
   550  
   551  func TestClearNonLocal(t *testing.T) {
   552  	tma := newTestMpoolAPI()
   553  	ds := datastore.NewMapDatastore()
   554  
   555  	mp, err := New(tma, ds, "mptest", nil)
   556  	if err != nil {
   557  		t.Fatal(err)
   558  	}
   559  
   560  	// the actors
   561  	w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
   562  	if err != nil {
   563  		t.Fatal(err)
   564  	}
   565  
   566  	a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
   567  	if err != nil {
   568  		t.Fatal(err)
   569  	}
   570  
   571  	w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
   572  	if err != nil {
   573  		t.Fatal(err)
   574  	}
   575  
   576  	a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
   577  	if err != nil {
   578  		t.Fatal(err)
   579  	}
   580  
   581  	tma.setBalance(a1, 1) // in FIL
   582  	tma.setBalance(a2, 1) // in FIL
   583  
   584  	gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
   585  	for i := 0; i < 10; i++ {
   586  		m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
   587  		_, err := mp.Push(m)
   588  		if err != nil {
   589  			t.Fatal(err)
   590  		}
   591  	}
   592  
   593  	for i := 0; i < 10; i++ {
   594  		m := makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
   595  		mustAdd(t, mp, m)
   596  	}
   597  
   598  	mp.Clear(false)
   599  
   600  	pending, _ := mp.Pending()
   601  	if len(pending) != 10 {
   602  		t.Fatalf("expected 10 pending messages, but got %d instead", len(pending))
   603  	}
   604  
   605  	for _, m := range pending {
   606  		if m.Message.From != a1 {
   607  			t.Fatalf("expected message from %s but got one from %s instead", a1, m.Message.From)
   608  		}
   609  	}
   610  }
   611  
   612  func TestUpdates(t *testing.T) {
   613  	tma := newTestMpoolAPI()
   614  	ds := datastore.NewMapDatastore()
   615  
   616  	mp, err := New(tma, ds, "mptest", nil)
   617  	if err != nil {
   618  		t.Fatal(err)
   619  	}
   620  
   621  	// the actors
   622  	w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
   623  	if err != nil {
   624  		t.Fatal(err)
   625  	}
   626  
   627  	a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
   628  	if err != nil {
   629  		t.Fatal(err)
   630  	}
   631  
   632  	w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
   633  	if err != nil {
   634  		t.Fatal(err)
   635  	}
   636  
   637  	a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
   638  	if err != nil {
   639  		t.Fatal(err)
   640  	}
   641  
   642  	ctx, cancel := context.WithCancel(context.TODO())
   643  	defer cancel()
   644  
   645  	ch, err := mp.Updates(ctx)
   646  	if err != nil {
   647  		t.Fatal(err)
   648  	}
   649  
   650  	gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
   651  
   652  	tma.setBalance(a1, 1) // in FIL
   653  	tma.setBalance(a2, 1) // in FIL
   654  
   655  	for i := 0; i < 10; i++ {
   656  		m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
   657  		_, err := mp.Push(m)
   658  		if err != nil {
   659  			t.Fatal(err)
   660  		}
   661  
   662  		_, ok := <-ch
   663  		if !ok {
   664  			t.Fatal("expected update, but got a closed channel instead")
   665  		}
   666  	}
   667  
   668  	err = mp.Close()
   669  	if err != nil {
   670  		t.Fatal(err)
   671  	}
   672  
   673  	_, ok := <-ch
   674  	if ok {
   675  		t.Fatal("expected closed channel, but got an update instead")
   676  	}
   677  }