diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 6163239e3..b421f7739 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -505,42 +505,16 @@ func (mp *MessagePool) getNonceLocked(addr address.Address, curTs *types.TipSet) } func (mp *MessagePool) getStateNonce(addr address.Address, curTs *types.TipSet) (uint64, error) { - // TODO: this method probably should be cached - - act, err := mp.api.StateGetActor(addr, curTs) + act, err := mp.api.GetActorAfter(addr, curTs) if err != nil { return 0, err } - baseNonce := act.Nonce - - // TODO: the correct thing to do here is probably to set curTs to chain.head - // but since we have an accurate view of the world until a head change occurs, - // this should be fine - if curTs == nil { - return baseNonce, nil - } - - msgs, err := mp.api.MessagesForTipset(curTs) - if err != nil { - return 0, xerrors.Errorf("failed to check messages for tipset: %w", err) - } - - for _, m := range msgs { - msg := m.VMMessage() - if msg.From == addr { - if msg.Nonce != baseNonce { - return 0, xerrors.Errorf("tipset %s has bad nonce ordering (%d != %d)", curTs.Cids(), msg.Nonce, baseNonce) - } - baseNonce++ - } - } - - return baseNonce, nil + return act.Nonce, nil } func (mp *MessagePool) getStateBalance(addr address.Address, ts *types.TipSet) (types.BigInt, error) { - act, err := mp.api.StateGetActor(addr, ts) + act, err := mp.api.GetActorAfter(addr, ts) if err != nil { return types.EmptyInt, err } @@ -832,7 +806,8 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) } for a, bkt := range buckets { - act, err := mp.api.StateGetActor(a, ts) + // TODO that might not be correct with GatActorAfter but it is only debug code + act, err := mp.api.GetActorAfter(a, ts) if err != nil { log.Debugf("%s, err: %s\n", a, err) continue diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 35e21f817..8fae79fa2 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -3,6 +3,7 @@ package messagepool import ( "context" "fmt" + "sort" "testing" "github.com/filecoin-project/go-address" @@ -33,11 +34,18 @@ type testMpoolAPI struct { } func newTestMpoolAPI() *testMpoolAPI { - return &testMpoolAPI{ + tma := &testMpoolAPI{ bmsgs: make(map[cid.Cid][]*types.SignedMessage), statenonce: make(map[address.Address]uint64), balance: make(map[address.Address]types.BigInt), } + genesis := mock.MkBlock(nil, 1, 1) + tma.setBlockMessages(genesis) + return tma +} + +func (tma *testMpoolAPI) nextBlock() *types.BlockHeader { + return mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1) } func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) { @@ -73,7 +81,7 @@ func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.S func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { tma.cb = cb - return nil + return tma.tipsets[0] } func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) { @@ -84,15 +92,38 @@ func (tma *testMpoolAPI) PubSubPublish(string, []byte) error { return nil } -func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { +func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) { balance, ok := tma.balance[addr] if !ok { balance = types.NewInt(1000e6) tma.balance[addr] = balance } + + msgs := make([]*types.SignedMessage, 0) + for _, b := range ts.Blocks() { + for _, m := range tma.bmsgs[b.Cid()] { + if m.Message.From == addr { + msgs = append(msgs, m) + } + } + } + + sort.Slice(msgs, func(i, j int) bool { + return msgs[i].Message.Nonce < msgs[j].Message.Nonce + }) + + nonce := tma.statenonce[addr] + + for _, m := range msgs { + if m.Message.Nonce != nonce { + break + } + nonce++ + } + return &types.Actor{ Code: builtin.StorageMarketActorCodeID, - Nonce: tma.statenonce[addr], + Nonce: nonce, Balance: balance, }, nil } @@ -178,7 +209,7 @@ func TestMessagePool(t *testing.T) { t.Fatal(err) } - a := mock.MkBlock(nil, 1, 1) + a := tma.nextBlock() sender, err := w.GenerateKey(crypto.SigTypeBLS) if err != nil { @@ -219,8 +250,8 @@ func TestRevertMessages(t *testing.T) { t.Fatal(err) } - a := mock.MkBlock(nil, 1, 1) - b := mock.MkBlock(mock.TipSet(a), 1, 1) + a := tma.nextBlock() + b := tma.nextBlock() sender, err := w.GenerateKey(crypto.SigTypeBLS) if err != nil { @@ -254,6 +285,7 @@ func TestRevertMessages(t *testing.T) { assertNonce(t, mp, sender, 4) p, _ := mp.Pending() + fmt.Printf("%+v\n", p) if len(p) != 3 { t.Fatal("expected three messages in mempool") } @@ -275,7 +307,7 @@ func TestPruningSimple(t *testing.T) { t.Fatal(err) } - a := mock.MkBlock(nil, 1, 1) + a := tma.nextBlock() tma.applyBlock(t, a) sender, err := w.GenerateKey(crypto.SigTypeBLS) diff --git a/chain/messagepool/provider.go b/chain/messagepool/provider.go index fa8b8ea83..80b9a4297 100644 --- a/chain/messagepool/provider.go +++ b/chain/messagepool/provider.go @@ -16,7 +16,7 @@ type Provider interface { SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet PutMessage(m types.ChainMsg) (cid.Cid, error) PubSubPublish(string, []byte) error - StateGetActor(address.Address, *types.TipSet) (*types.Actor, error) + GetActorAfter(address.Address, *types.TipSet) (*types.Actor, error) StateAccountKey(context.Context, address.Address, *types.TipSet) (address.Address, error) MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error) @@ -46,9 +46,14 @@ func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error { return mpp.ps.Publish(k, v) //nolint } -func (mpp *mpoolProvider) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { +func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) { var act types.Actor - return &act, mpp.sm.WithParentState(ts, mpp.sm.WithActor(addr, stmgr.GetActor(&act))) + stcid, _, err := mpp.sm.TipSetState(context.TODO(), ts) + if err != nil { + return nil, xerrors.Errorf("computing tipset state for GetActor: %w", err) + } + + return &act, mpp.sm.WithStateTree(stcid, mpp.sm.WithActor(addr, stmgr.GetActor(&act))) } func (mpp *mpoolProvider) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index ab0326896..b39eb01cb 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -604,7 +604,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 // cannot exceed the block limit; drop all messages that exceed the limit // - the total gasReward cannot exceed the actor's balance; drop all messages that exceed // the balance - a, err := mp.api.StateGetActor(actor, ts) + a, err := mp.api.GetActorAfter(actor, ts) if err != nil { log.Errorf("failed to load actor state, not building chain for %s: %w", actor, err) return nil diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 0032db23c..f5c947954 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -464,7 +464,7 @@ func TestBasicMessageSelection(t *testing.T) { // now create another set of messages and add them to the mpool for i := 20; i < 30; i++ { - m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(2*i+1)) + m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(2*i+200)) mustAdd(t, mp, m) m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1)) mustAdd(t, mp, m) @@ -480,12 +480,12 @@ func TestBasicMessageSelection(t *testing.T) { if err != nil { t.Fatal(err) } - if len(msgs) != 40 { - t.Fatalf("expected 40 messages, got %d", len(msgs)) + if len(msgs) != 20 { + t.Fatalf("expected 20 messages, got %d", len(msgs)) } - nextNonce = 10 - for i := 0; i < 20; i++ { + nextNonce = 20 + for i := 0; i < 10; i++ { if msgs[i].Message.From != a1 { t.Fatalf("expected message from actor a1") } @@ -495,8 +495,8 @@ func TestBasicMessageSelection(t *testing.T) { nextNonce++ } - nextNonce = 10 - for i := 20; i < 40; i++ { + nextNonce = 20 + for i := 10; i < 20; i++ { if msgs[i].Message.From != a2 { t.Fatalf("expected message from actor a2") }