From d782250abaa89b047e415e28a050230950b6ebb2 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 23 Mar 2021 16:55:38 +0200 Subject: [PATCH] implement MessagePool.CheckReplaceMessages Signed-off-by: Jakub Sztandera --- api/api_full.go | 2 ++ api/mocks/mock_full.go | 15 ++++++++++ api/proxy_gen.go | 10 +++++++ chain/messagepool/check.go | 45 ++++++++++++++++++++++++++++++ documentation/en/api-v0-methods.md | 16 +++++++++++ node/impl/full/mpool.go | 4 +++ 6 files changed, 92 insertions(+) diff --git a/api/api_full.go b/api/api_full.go index 3b69ca5e6..148f4ac92 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -256,6 +256,8 @@ type FullNode interface { MpoolCheckMessages(context.Context, []*types.Message) ([][]MessageCheckStatus, error) //perm:read // MpoolCheckPendingMessages performs logical checks for all pending messages from a given address MpoolCheckPendingMessages(context.Context, address.Address) ([][]MessageCheckStatus, error) //perm:read + // MpoolCheckReplaceMessages performs logical checks on pending messages with replacement + MpoolCheckReplaceMessages(context.Context, []*types.Message) ([][]MessageCheckStatus, error) //perm:read // MpoolGetNonce gets next nonce for the specified sender. // Note that this method may not be atomic. Use MpoolPushMessage instead. diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 891a3637f..ee89a1d23 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -1098,6 +1098,21 @@ func (mr *MockFullNodeMockRecorder) MpoolCheckPendingMessages(arg0, arg1 interfa return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MpoolCheckPendingMessages", reflect.TypeOf((*MockFullNode)(nil).MpoolCheckPendingMessages), arg0, arg1) } +// MpoolCheckReplaceMessages mocks base method +func (m *MockFullNode) MpoolCheckReplaceMessages(arg0 context.Context, arg1 []*types.Message) ([][]api.MessageCheckStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MpoolCheckReplaceMessages", arg0, arg1) + ret0, _ := ret[0].([][]api.MessageCheckStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MpoolCheckReplaceMessages indicates an expected call of MpoolCheckReplaceMessages +func (mr *MockFullNodeMockRecorder) MpoolCheckReplaceMessages(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MpoolCheckReplaceMessages", reflect.TypeOf((*MockFullNode)(nil).MpoolCheckReplaceMessages), arg0, arg1) +} + // MpoolClear mocks base method func (m *MockFullNode) MpoolClear(arg0 context.Context, arg1 bool) error { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 08a9c0dd8..dfb9f3731 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -239,6 +239,8 @@ type FullNodeStruct struct { MpoolCheckPendingMessages func(p0 context.Context, p1 address.Address) ([][]MessageCheckStatus, error) `perm:"read"` + MpoolCheckReplaceMessages func(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) `perm:"read"` + MpoolClear func(p0 context.Context, p1 bool) error `perm:"write"` MpoolGetConfig func(p0 context.Context) (*types.MpoolConfig, error) `perm:"read"` @@ -1529,6 +1531,14 @@ func (s *FullNodeStub) MpoolCheckPendingMessages(p0 context.Context, p1 address. return *new([][]MessageCheckStatus), xerrors.New("method not supported") } +func (s *FullNodeStruct) MpoolCheckReplaceMessages(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) { + return s.Internal.MpoolCheckReplaceMessages(p0, p1) +} + +func (s *FullNodeStub) MpoolCheckReplaceMessages(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) { + return *new([][]MessageCheckStatus), xerrors.New("method not supported") +} + func (s *FullNodeStruct) MpoolClear(p0 context.Context, p1 bool) error { return s.Internal.MpoolClear(p0, p1) } diff --git a/chain/messagepool/check.go b/chain/messagepool/check.go index 9a8e32248..5b0761a62 100644 --- a/chain/messagepool/check.go +++ b/chain/messagepool/check.go @@ -46,6 +46,51 @@ func (mp *MessagePool) CheckPendingMessages(from address.Address) ([][]api.Messa return mp.checkMessages(msgs, true) } +// CheckReplaceMessages performs a set of logical checks for related messages while performing a +// replacement. +func (mp *MessagePool) CheckReplaceMessages(replace []*types.Message) ([][]api.MessageCheckStatus, error) { + msgMap := make(map[address.Address]map[uint64]*types.Message) + count := 0 + + mp.lk.Lock() + for _, m := range replace { + mmap, ok := msgMap[m.From] + if !ok { + mmap = make(map[uint64]*types.Message) + msgMap[m.From] = mmap + mset, ok := mp.pending[m.From] + if ok { + count += len(mset.msgs) + for _, sm := range mset.msgs { + mmap[sm.Message.Nonce] = &sm.Message + } + } else { + count++ + } + } + mmap[m.Nonce] = m + } + mp.lk.Unlock() + + msgs := make([]*types.Message, 0, count) + start := 0 + for _, mmap := range msgMap { + end := start + len(mmap) + + for _, m := range mmap { + msgs = append(msgs, m) + } + + sort.Slice(msgs[start:end], func(i, j int) bool { + return msgs[start+i].Nonce < msgs[start+j].Nonce + }) + + start = end + } + + return mp.checkMessages(msgs, true) +} + func (mp *MessagePool) checkMessages(msgs []*types.Message, interned bool) (result [][]api.MessageCheckStatus, err error) { mp.curTsLk.Lock() curTs := mp.curTs diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 2b75212c2..e90ba7d6a 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -84,6 +84,7 @@ * [MpoolBatchPushUntrusted](#MpoolBatchPushUntrusted) * [MpoolCheckMessages](#MpoolCheckMessages) * [MpoolCheckPendingMessages](#MpoolCheckPendingMessages) + * [MpoolCheckReplaceMessages](#MpoolCheckReplaceMessages) * [MpoolClear](#MpoolClear) * [MpoolGetConfig](#MpoolGetConfig) * [MpoolGetNonce](#MpoolGetNonce) @@ -2026,6 +2027,21 @@ Inputs: Response: `null` +### MpoolCheckReplaceMessages +MpoolCheckMessages performs logical checks on pending messages with replacement + + +Perms: read + +Inputs: +```json +[ + null +] +``` + +Response: `null` + ### MpoolClear MpoolClear clears pending messages from the mpool diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 4916af894..099fb45b8 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -233,6 +233,10 @@ func (a *MpoolAPI) MpoolCheckPendingMessages(ctx context.Context, from address.A return a.Mpool.CheckPendingMessages(from) } +func (a *MpoolAPI) MpoolCheckReplaceMessages(ctx context.Context, msgs []*types.Message) ([][]api.MessageCheckStatus, error) { + return a.Mpool.CheckReplaceMessages(msgs) +} + func (a *MpoolAPI) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) { return a.Mpool.GetNonce(ctx, addr, types.EmptyTSK) }