diff --git a/action/protocol/mock_protocol.go b/action/protocol/mock_protocol.go index ebdf0ed9dd..e9ea48eaf7 100644 --- a/action/protocol/mock_protocol.go +++ b/action/protocol/mock_protocol.go @@ -488,20 +488,6 @@ func (m *MockView) EXPECT() *MockViewMockRecorder { return m.recorder } -// Clone mocks base method. -func (m *MockView) Clone() View { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Clone") - ret0, _ := ret[0].(View) - return ret0 -} - -// Clone indicates an expected call of Clone. -func (mr *MockViewMockRecorder) Clone() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clone", reflect.TypeOf((*MockView)(nil).Clone)) -} - // Commit mocks base method. func (m *MockView) Commit(arg0 context.Context, arg1 StateManager) error { m.ctrl.T.Helper() @@ -516,6 +502,20 @@ func (mr *MockViewMockRecorder) Commit(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockView)(nil).Commit), arg0, arg1) } +// Fork mocks base method. +func (m *MockView) Fork() View { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Fork") + ret0, _ := ret[0].(View) + return ret0 +} + +// Fork indicates an expected call of Fork. +func (mr *MockViewMockRecorder) Fork() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fork", reflect.TypeOf((*MockView)(nil).Fork)) +} + // Revert mocks base method. func (m *MockView) Revert(arg0 int) error { m.ctrl.T.Helper() diff --git a/action/protocol/staking/candidate_statereader.go b/action/protocol/staking/candidate_statereader.go index d12d498ffe..402e00c06d 100644 --- a/action/protocol/staking/candidate_statereader.go +++ b/action/protocol/staking/candidate_statereader.go @@ -46,7 +46,7 @@ type ( NativeBucketIndicesByVoter(addr address.Address) (*BucketIndices, uint64, error) NativeBucketIndicesByCandidate(addr address.Address) (*BucketIndices, uint64, error) CandidateByAddress(name address.Address) (*Candidate, uint64, error) - getAllCandidates() (CandidateList, uint64, error) + CreateCandidateCenter() (*CandidateCenter, uint64, error) ReadState Height() uint64 SR() protocol.StateReader @@ -152,12 +152,7 @@ func CreateBaseView(sr protocol.StateReader, enableSMStorage bool) (*viewData, u } csr := newCandidateStateReader(sr) - all, height, err := csr.getAllCandidates() - if err != nil && errors.Cause(err) != state.ErrStateNotExist { - return nil, height, err - } - - center, err := NewCandidateCenter(all) + center, height, err := csr.CreateCandidateCenter() if err != nil { return nil, height, err } @@ -301,21 +296,29 @@ func (c *candSR) CandidateByAddress(name address.Address) (*Candidate, uint64, e return &d, height, err } -func (c *candSR) getAllCandidates() (CandidateList, uint64, error) { +func (c *candSR) CreateCandidateCenter() (*CandidateCenter, uint64, error) { height, iter, err := c.States(protocol.NamespaceOption(_candidateNameSpace)) + var cands CandidateList + switch errors.Cause(err) { + case nil: + cands = make(CandidateList, 0, iter.Size()) + for i := 0; i < iter.Size(); i++ { + c := &Candidate{} + if _, err := iter.Next(c); err != nil { + return nil, height, errors.Wrapf(err, "failed to deserialize candidate") + } + cands = append(cands, c) + } + case state.ErrStateNotExist: + default: + return nil, height, err + } + center, err := NewCandidateCenter(cands) if err != nil { return nil, height, err } - cands := make(CandidateList, 0, iter.Size()) - for i := 0; i < iter.Size(); i++ { - c := &Candidate{} - if _, err := iter.Next(c); err != nil { - return nil, height, errors.Wrapf(err, "failed to deserialize candidate") - } - cands = append(cands, c) - } - return cands, height, nil + return center, height, nil } func (c *candSR) NewBucketPool(enableSMStorage bool) (*BucketPool, error) { diff --git a/action/protocol/staking/candidate_test.go b/action/protocol/staking/candidate_test.go index 56ddad626b..3ffb380f43 100644 --- a/action/protocol/staking/candidate_test.go +++ b/action/protocol/staking/candidate_test.go @@ -214,8 +214,9 @@ func TestGetPutCandidate(t *testing.T) { } // get all candidates - all, _, err := csr.getAllCandidates() + cc, _, err := csr.CreateCandidateCenter() require.NoError(err) + all := cc.All() require.Equal(len(testCandidates), len(all)) for _, e := range testCandidates { for i := range all { diff --git a/action/protocol/staking/contractstake_indexer.go b/action/protocol/staking/contractstake_indexer.go index 4d8568389e..ebe0b1952f 100644 --- a/action/protocol/staking/contractstake_indexer.go +++ b/action/protocol/staking/contractstake_indexer.go @@ -13,7 +13,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/v2/action" "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking/contractstaking" ) var ( @@ -25,7 +27,18 @@ var ( ) type ( - + // EventHandler is the interface for handling staking events + EventHandler interface { + PutBucketType(address.Address, *ContractStakingBucketType) error + DeductBucket(address.Address, uint64) (*contractstaking.Bucket, error) + PutBucket(address.Address, uint64, *contractstaking.Bucket) error + DeleteBucket(address.Address, uint64) error + } + // EventProcessor is the interface for processing staking events + EventProcessor interface { + // ProcessReceipts processes receipts + ProcessReceipts(context.Context, ...*action.Receipt) error + } // ContractStakingIndexer defines the interface of contract staking reader ContractStakingIndexer interface { Height() (uint64, error) @@ -41,6 +54,8 @@ type ( ContractAddress() address.Address // LoadStakeView loads the contract stake view from state reader LoadStakeView(context.Context, protocol.StateReader) (ContractStakeView, error) + // CreateEventProcessor creates a new event processor + CreateEventProcessor(context.Context, EventHandler) EventProcessor } // ContractStakingIndexerWithBucketType defines the interface of contract staking reader with bucket type ContractStakingIndexerWithBucketType interface { diff --git a/action/protocol/staking/contractstake_indexer_mock.go b/action/protocol/staking/contractstake_indexer_mock.go index 1c049bc48d..23991ee16f 100644 --- a/action/protocol/staking/contractstake_indexer_mock.go +++ b/action/protocol/staking/contractstake_indexer_mock.go @@ -14,10 +14,136 @@ import ( reflect "reflect" address "github.com/iotexproject/iotex-address/address" + action "github.com/iotexproject/iotex-core/v2/action" protocol "github.com/iotexproject/iotex-core/v2/action/protocol" + contractstaking "github.com/iotexproject/iotex-core/v2/action/protocol/staking/contractstaking" gomock "go.uber.org/mock/gomock" ) +// MockEventHandler is a mock of EventHandler interface. +type MockEventHandler struct { + ctrl *gomock.Controller + recorder *MockEventHandlerMockRecorder + isgomock struct{} +} + +// MockEventHandlerMockRecorder is the mock recorder for MockEventHandler. +type MockEventHandlerMockRecorder struct { + mock *MockEventHandler +} + +// NewMockEventHandler creates a new mock instance. +func NewMockEventHandler(ctrl *gomock.Controller) *MockEventHandler { + mock := &MockEventHandler{ctrl: ctrl} + mock.recorder = &MockEventHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEventHandler) EXPECT() *MockEventHandlerMockRecorder { + return m.recorder +} + +// DeductBucket mocks base method. +func (m *MockEventHandler) DeductBucket(arg0 address.Address, arg1 uint64) (*contractstaking.Bucket, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeductBucket", arg0, arg1) + ret0, _ := ret[0].(*contractstaking.Bucket) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeductBucket indicates an expected call of DeductBucket. +func (mr *MockEventHandlerMockRecorder) DeductBucket(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeductBucket", reflect.TypeOf((*MockEventHandler)(nil).DeductBucket), arg0, arg1) +} + +// DeleteBucket mocks base method. +func (m *MockEventHandler) DeleteBucket(arg0 address.Address, arg1 uint64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteBucket", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteBucket indicates an expected call of DeleteBucket. +func (mr *MockEventHandlerMockRecorder) DeleteBucket(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBucket", reflect.TypeOf((*MockEventHandler)(nil).DeleteBucket), arg0, arg1) +} + +// PutBucket mocks base method. +func (m *MockEventHandler) PutBucket(arg0 address.Address, arg1 uint64, arg2 *contractstaking.Bucket) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PutBucket", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// PutBucket indicates an expected call of PutBucket. +func (mr *MockEventHandlerMockRecorder) PutBucket(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutBucket", reflect.TypeOf((*MockEventHandler)(nil).PutBucket), arg0, arg1, arg2) +} + +// PutBucketType mocks base method. +func (m *MockEventHandler) PutBucketType(arg0 address.Address, arg1 *ContractStakingBucketType) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PutBucketType", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// PutBucketType indicates an expected call of PutBucketType. +func (mr *MockEventHandlerMockRecorder) PutBucketType(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutBucketType", reflect.TypeOf((*MockEventHandler)(nil).PutBucketType), arg0, arg1) +} + +// MockEventProcessor is a mock of EventProcessor interface. +type MockEventProcessor struct { + ctrl *gomock.Controller + recorder *MockEventProcessorMockRecorder + isgomock struct{} +} + +// MockEventProcessorMockRecorder is the mock recorder for MockEventProcessor. +type MockEventProcessorMockRecorder struct { + mock *MockEventProcessor +} + +// NewMockEventProcessor creates a new mock instance. +func NewMockEventProcessor(ctrl *gomock.Controller) *MockEventProcessor { + mock := &MockEventProcessor{ctrl: ctrl} + mock.recorder = &MockEventProcessorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEventProcessor) EXPECT() *MockEventProcessorMockRecorder { + return m.recorder +} + +// ProcessReceipts mocks base method. +func (m *MockEventProcessor) ProcessReceipts(arg0 context.Context, arg1 ...*action.Receipt) error { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ProcessReceipts", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// ProcessReceipts indicates an expected call of ProcessReceipts. +func (mr *MockEventProcessorMockRecorder) ProcessReceipts(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessReceipts", reflect.TypeOf((*MockEventProcessor)(nil).ProcessReceipts), varargs...) +} + // MockContractStakingIndexer is a mock of ContractStakingIndexer interface. type MockContractStakingIndexer struct { ctrl *gomock.Controller @@ -101,6 +227,20 @@ func (mr *MockContractStakingIndexerMockRecorder) ContractAddress() *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractAddress", reflect.TypeOf((*MockContractStakingIndexer)(nil).ContractAddress)) } +// CreateEventProcessor mocks base method. +func (m *MockContractStakingIndexer) CreateEventProcessor(arg0 context.Context, arg1 EventHandler) EventProcessor { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateEventProcessor", arg0, arg1) + ret0, _ := ret[0].(EventProcessor) + return ret0 +} + +// CreateEventProcessor indicates an expected call of CreateEventProcessor. +func (mr *MockContractStakingIndexerMockRecorder) CreateEventProcessor(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEventProcessor", reflect.TypeOf((*MockContractStakingIndexer)(nil).CreateEventProcessor), arg0, arg1) +} + // Height mocks base method. func (m *MockContractStakingIndexer) Height() (uint64, error) { m.ctrl.T.Helper() @@ -244,6 +384,20 @@ func (mr *MockContractStakingIndexerWithBucketTypeMockRecorder) ContractAddress( return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractAddress", reflect.TypeOf((*MockContractStakingIndexerWithBucketType)(nil).ContractAddress)) } +// CreateEventProcessor mocks base method. +func (m *MockContractStakingIndexerWithBucketType) CreateEventProcessor(arg0 context.Context, arg1 EventHandler) EventProcessor { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateEventProcessor", arg0, arg1) + ret0, _ := ret[0].(EventProcessor) + return ret0 +} + +// CreateEventProcessor indicates an expected call of CreateEventProcessor. +func (mr *MockContractStakingIndexerWithBucketTypeMockRecorder) CreateEventProcessor(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEventProcessor", reflect.TypeOf((*MockContractStakingIndexerWithBucketType)(nil).CreateEventProcessor), arg0, arg1) +} + // Height mocks base method. func (m *MockContractStakingIndexerWithBucketType) Height() (uint64, error) { m.ctrl.T.Helper() diff --git a/action/protocol/staking/contractstaking/bucket.go b/action/protocol/staking/contractstaking/bucket.go index 91429ed37c..703becee88 100644 --- a/action/protocol/staking/contractstaking/bucket.go +++ b/action/protocol/staking/contractstaking/bucket.go @@ -35,6 +35,9 @@ type ( } ) +// ErrBucketNotExist is the error when bucket does not exist +var ErrBucketNotExist = errors.New("bucket does not exist") + func (b *Bucket) toProto() *stakingpb.SystemStakingBucket { if b == nil { return nil diff --git a/action/protocol/staking/contractstaking/statemanager.go b/action/protocol/staking/contractstaking/statemanager.go index 42964cb90e..b376a2f84f 100644 --- a/action/protocol/staking/contractstaking/statemanager.go +++ b/action/protocol/staking/contractstaking/statemanager.go @@ -33,7 +33,7 @@ func (cs *ContractStakingStateManager) UpsertBucketType(contractAddr address.Add // DeleteBucket removes a bucket for a given contract and bucket ID. func (cs *ContractStakingStateManager) DeleteBucket(contractAddr address.Address, bucketID uint64) error { _, err := cs.sm.DelState( - bucketTypeNamespaceOption(contractAddr), + contractNamespaceOption(contractAddr), bucketIDKeyOption(bucketID), ) diff --git a/action/protocol/staking/protocol.go b/action/protocol/staking/protocol.go index 3436021c0c..55010f3340 100644 --- a/action/protocol/staking/protocol.go +++ b/action/protocol/staking/protocol.go @@ -472,11 +472,11 @@ func (p *Protocol) handleStakingIndexer(ctx context.Context, epochStartHeight ui if err != nil { return err } - all, _, err := csr.getAllCandidates() - if err != nil && errors.Cause(err) != state.ErrStateNotExist { + cc, _, err := csr.CreateCandidateCenter() + if err != nil { return err } - candidateList, err := toIoTeXTypesCandidateListV2(csr, all, protocol.MustGetFeatureCtx(ctx)) + candidateList, err := toIoTeXTypesCandidateListV2(csr, cc.All(), protocol.MustGetFeatureCtx(ctx)) if err != nil { return err } diff --git a/action/protocol/staking/protocol_test.go b/action/protocol/staking/protocol_test.go index 6a62ebeafe..afa55c88d7 100644 --- a/action/protocol/staking/protocol_test.go +++ b/action/protocol/staking/protocol_test.go @@ -102,9 +102,9 @@ func TestProtocol(t *testing.T) { buckets, _, err := csr.NativeBuckets() r.NoError(err) r.Equal(0, len(buckets)) - c, _, err := csr.getAllCandidates() - r.Equal(state.ErrStateNotExist, err) - r.Equal(0, len(c)) + cc, _, err := csr.CreateCandidateCenter() + r.NoError(err) + r.Equal(0, len(cc.All())) // address package also defined protocol address, make sure they match r.Equal(stk.addr.Bytes(), address.StakingProtocolAddrHash[:]) @@ -162,8 +162,9 @@ func TestProtocol(t *testing.T) { } // load all candidates from stateDB and verify - all, _, err := csr.getAllCandidates() + cc, _, err = csr.CreateCandidateCenter() r.NoError(err) + all := cc.All() r.Equal(len(testCandidates), len(all)) for _, e := range testCandidates { for i := range all { @@ -188,8 +189,10 @@ func TestProtocol(t *testing.T) { // delete one bucket r.NoError(csm.delBucket(1)) buckets, _, err = csr.NativeBuckets() + require.NoError(t, err) r.NoError(csm.delBucket(1)) buckets, _, err = csr.NativeBuckets() + require.NoError(t, err) for _, e := range tests { for i := range buckets { if buckets[i].StakedAmount == e.amount { diff --git a/action/protocol/staking/viewdata.go b/action/protocol/staking/viewdata.go index ece4958849..10f0f9dac5 100644 --- a/action/protocol/staking/viewdata.go +++ b/action/protocol/staking/viewdata.go @@ -30,8 +30,8 @@ type ( CreatePreStates(ctx context.Context) error // Handle handles the receipt for the contract stake view Handle(ctx context.Context, receipt *action.Receipt) error - // WriteBuckets writes the buckets to the state manager - WriteBuckets(protocol.StateManager) error + // Migrate migrate the buckets to the state manager + Migrate(protocol.StateManager) error // BucketsByCandidate returns the buckets by candidate address BucketsByCandidate(ownerAddr address.Address) ([]*VoteBucket, error) AddBlockReceipts(ctx context.Context, receipts []*action.Receipt) error @@ -130,17 +130,17 @@ func (v *viewData) Revert(snapshot int) error { func (csv *contractStakeView) FlushBuckets(sm protocol.StateManager) error { if csv.v1 != nil { - if err := csv.v1.WriteBuckets(sm); err != nil { + if err := csv.v1.Migrate(sm); err != nil { return err } } if csv.v2 != nil { - if err := csv.v2.WriteBuckets(sm); err != nil { + if err := csv.v2.Migrate(sm); err != nil { return err } } if csv.v3 != nil { - if err := csv.v3.WriteBuckets(sm); err != nil { + if err := csv.v3.Migrate(sm); err != nil { return err } } diff --git a/action/protocol/staking/vote_reviser.go b/action/protocol/staking/vote_reviser.go index 844d0c324a..472fb99494 100644 --- a/action/protocol/staking/vote_reviser.go +++ b/action/protocol/staking/vote_reviser.go @@ -42,12 +42,11 @@ func NewVoteReviser(cfg ReviseConfig) *VoteReviser { // Revise recalculate candidate votes on preset revising height. func (vr *VoteReviser) Revise(ctx protocol.FeatureCtx, csm CandidateStateManager, height uint64) error { if !vr.isCacheExist(height) { - cands, _, err := newCandidateStateReader(csm.SM()).getAllCandidates() - switch { - case errors.Cause(err) == state.ErrStateNotExist: - case err != nil: + cc, _, err := newCandidateStateReader(csm.SM()).CreateCandidateCenter() + if err != nil { return err } + cands := cc.All() if vr.shouldCorrectCandSelfStake(height) { cands, err = vr.correctCandSelfStake(ctx, csm, height, cands) if err != nil { diff --git a/api/mock_apicoreservice.go b/api/mock_apicoreservice.go index fa073c4496..d7c0e241f1 100644 --- a/api/mock_apicoreservice.go +++ b/api/mock_apicoreservice.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./api/coreservice.go +// +// Generated by this command: +// +// mockgen -destination=./api/mock_apicoreservice.go -source=./api/coreservice.go -package=api CoreService +// // Package api is a generated GoMock package. package api @@ -13,22 +18,22 @@ import ( tracers "github.com/ethereum/go-ethereum/eth/tracers" hash "github.com/iotexproject/go-pkgs/hash" address "github.com/iotexproject/iotex-address/address" - iotexapi "github.com/iotexproject/iotex-proto/golang/iotexapi" - iotextypes "github.com/iotexproject/iotex-proto/golang/iotextypes" - gomock "go.uber.org/mock/gomock" - action "github.com/iotexproject/iotex-core/v2/action" protocol "github.com/iotexproject/iotex-core/v2/action/protocol" logfilter "github.com/iotexproject/iotex-core/v2/api/logfilter" - types "github.com/iotexproject/iotex-core/v2/api/types" + apitypes "github.com/iotexproject/iotex-core/v2/api/types" block "github.com/iotexproject/iotex-core/v2/blockchain/block" genesis "github.com/iotexproject/iotex-core/v2/blockchain/genesis" + iotexapi "github.com/iotexproject/iotex-proto/golang/iotexapi" + iotextypes "github.com/iotexproject/iotex-proto/golang/iotextypes" + gomock "go.uber.org/mock/gomock" ) // MockCoreService is a mock of CoreService interface. type MockCoreService struct { ctrl *gomock.Controller recorder *MockCoreServiceMockRecorder + isgomock struct{} } // MockCoreServiceMockRecorder is the mock recorder for MockCoreService. @@ -59,7 +64,7 @@ func (m *MockCoreService) Account(addr address.Address) (*iotextypes.AccountMeta } // Account indicates an expected call of Account. -func (mr *MockCoreServiceMockRecorder) Account(addr interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) Account(addr any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Account", reflect.TypeOf((*MockCoreService)(nil).Account), addr) } @@ -74,7 +79,7 @@ func (m *MockCoreService) Action(actionHash string, checkPending bool) (*iotexap } // Action indicates an expected call of Action. -func (mr *MockCoreServiceMockRecorder) Action(actionHash, checkPending interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) Action(actionHash, checkPending any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Action", reflect.TypeOf((*MockCoreService)(nil).Action), actionHash, checkPending) } @@ -91,7 +96,7 @@ func (m *MockCoreService) ActionByActionHash(h hash.Hash256) (*action.SealedEnve } // ActionByActionHash indicates an expected call of ActionByActionHash. -func (mr *MockCoreServiceMockRecorder) ActionByActionHash(h interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ActionByActionHash(h any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActionByActionHash", reflect.TypeOf((*MockCoreService)(nil).ActionByActionHash), h) } @@ -106,7 +111,7 @@ func (m *MockCoreService) Actions(start, count uint64) ([]*iotexapi.ActionInfo, } // Actions indicates an expected call of Actions. -func (mr *MockCoreServiceMockRecorder) Actions(start, count interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) Actions(start, count any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Actions", reflect.TypeOf((*MockCoreService)(nil).Actions), start, count) } @@ -121,7 +126,7 @@ func (m *MockCoreService) ActionsByAddress(addr address.Address, start, count ui } // ActionsByAddress indicates an expected call of ActionsByAddress. -func (mr *MockCoreServiceMockRecorder) ActionsByAddress(addr, start, count interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ActionsByAddress(addr, start, count any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActionsByAddress", reflect.TypeOf((*MockCoreService)(nil).ActionsByAddress), addr, start, count) } @@ -136,7 +141,7 @@ func (m *MockCoreService) ActionsInActPool(actHashes []string) ([]*action.Sealed } // ActionsInActPool indicates an expected call of ActionsInActPool. -func (mr *MockCoreServiceMockRecorder) ActionsInActPool(actHashes interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ActionsInActPool(actHashes any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActionsInActPool", reflect.TypeOf((*MockCoreService)(nil).ActionsInActPool), actHashes) } @@ -151,67 +156,67 @@ func (m *MockCoreService) BalanceAt(ctx context.Context, addr address.Address, h } // BalanceAt indicates an expected call of BalanceAt. -func (mr *MockCoreServiceMockRecorder) BalanceAt(ctx, addr, height interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) BalanceAt(ctx, addr, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BalanceAt", reflect.TypeOf((*MockCoreService)(nil).BalanceAt), ctx, addr, height) } // BlobSidecarsByHeight mocks base method. -func (m *MockCoreService) BlobSidecarsByHeight(height uint64) ([]*types.BlobSidecarResult, error) { +func (m *MockCoreService) BlobSidecarsByHeight(height uint64) ([]*apitypes.BlobSidecarResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlobSidecarsByHeight", height) - ret0, _ := ret[0].([]*types.BlobSidecarResult) + ret0, _ := ret[0].([]*apitypes.BlobSidecarResult) ret1, _ := ret[1].(error) return ret0, ret1 } // BlobSidecarsByHeight indicates an expected call of BlobSidecarsByHeight. -func (mr *MockCoreServiceMockRecorder) BlobSidecarsByHeight(height interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) BlobSidecarsByHeight(height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlobSidecarsByHeight", reflect.TypeOf((*MockCoreService)(nil).BlobSidecarsByHeight), height) } // BlockByHash mocks base method. -func (m *MockCoreService) BlockByHash(arg0 string) (*types.BlockWithReceipts, error) { +func (m *MockCoreService) BlockByHash(arg0 string) (*apitypes.BlockWithReceipts, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockByHash", arg0) - ret0, _ := ret[0].(*types.BlockWithReceipts) + ret0, _ := ret[0].(*apitypes.BlockWithReceipts) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByHash indicates an expected call of BlockByHash. -func (mr *MockCoreServiceMockRecorder) BlockByHash(arg0 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) BlockByHash(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockCoreService)(nil).BlockByHash), arg0) } // BlockByHeight mocks base method. -func (m *MockCoreService) BlockByHeight(arg0 uint64) (*types.BlockWithReceipts, error) { +func (m *MockCoreService) BlockByHeight(arg0 uint64) (*apitypes.BlockWithReceipts, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockByHeight", arg0) - ret0, _ := ret[0].(*types.BlockWithReceipts) + ret0, _ := ret[0].(*apitypes.BlockWithReceipts) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByHeight indicates an expected call of BlockByHeight. -func (mr *MockCoreServiceMockRecorder) BlockByHeight(arg0 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) BlockByHeight(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockCoreService)(nil).BlockByHeight), arg0) } // BlockByHeightRange mocks base method. -func (m *MockCoreService) BlockByHeightRange(arg0, arg1 uint64) ([]*types.BlockWithReceipts, error) { +func (m *MockCoreService) BlockByHeightRange(arg0, arg1 uint64) ([]*apitypes.BlockWithReceipts, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockByHeightRange", arg0, arg1) - ret0, _ := ret[0].([]*types.BlockWithReceipts) + ret0, _ := ret[0].([]*apitypes.BlockWithReceipts) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByHeightRange indicates an expected call of BlockByHeightRange. -func (mr *MockCoreServiceMockRecorder) BlockByHeightRange(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) BlockByHeightRange(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeightRange", reflect.TypeOf((*MockCoreService)(nil).BlockByHeightRange), arg0, arg1) } @@ -226,7 +231,7 @@ func (m *MockCoreService) BlockHashByBlockHeight(blkHeight uint64) (hash.Hash256 } // BlockHashByBlockHeight indicates an expected call of BlockHashByBlockHeight. -func (mr *MockCoreServiceMockRecorder) BlockHashByBlockHeight(blkHeight interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) BlockHashByBlockHeight(blkHeight any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockHashByBlockHeight", reflect.TypeOf((*MockCoreService)(nil).BlockHashByBlockHeight), blkHeight) } @@ -246,10 +251,10 @@ func (mr *MockCoreServiceMockRecorder) ChainID() *gomock.Call { } // ChainListener mocks base method. -func (m *MockCoreService) ChainListener() types.Listener { +func (m *MockCoreService) ChainListener() apitypes.Listener { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ChainListener") - ret0, _ := ret[0].(types.Listener) + ret0, _ := ret[0].(apitypes.Listener) return ret0 } @@ -285,7 +290,7 @@ func (m *MockCoreService) CodeAt(ctx context.Context, addr address.Address, heig } // CodeAt indicates an expected call of CodeAt. -func (mr *MockCoreServiceMockRecorder) CodeAt(ctx, addr, height interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) CodeAt(ctx, addr, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CodeAt", reflect.TypeOf((*MockCoreService)(nil).CodeAt), ctx, addr, height) } @@ -314,7 +319,7 @@ func (m *MockCoreService) ElectionBuckets(epochNum uint64) ([]*iotextypes.Electi } // ElectionBuckets indicates an expected call of ElectionBuckets. -func (mr *MockCoreServiceMockRecorder) ElectionBuckets(epochNum interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ElectionBuckets(epochNum any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ElectionBuckets", reflect.TypeOf((*MockCoreService)(nil).ElectionBuckets), epochNum) } @@ -331,7 +336,7 @@ func (m *MockCoreService) EpochMeta(epochNum uint64) (*iotextypes.EpochData, uin } // EpochMeta indicates an expected call of EpochMeta. -func (mr *MockCoreServiceMockRecorder) EpochMeta(epochNum interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) EpochMeta(epochNum any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochMeta", reflect.TypeOf((*MockCoreService)(nil).EpochMeta), epochNum) } @@ -339,7 +344,7 @@ func (mr *MockCoreServiceMockRecorder) EpochMeta(epochNum interface{}) *gomock.C // EstimateExecutionGasConsumption mocks base method. func (m *MockCoreService) EstimateExecutionGasConsumption(ctx context.Context, sc action.Envelope, callerAddr address.Address, opts ...protocol.SimulateOption) (uint64, []byte, error) { m.ctrl.T.Helper() - varargs := []interface{}{ctx, sc, callerAddr} + varargs := []any{ctx, sc, callerAddr} for _, a := range opts { varargs = append(varargs, a) } @@ -351,16 +356,16 @@ func (m *MockCoreService) EstimateExecutionGasConsumption(ctx context.Context, s } // EstimateExecutionGasConsumption indicates an expected call of EstimateExecutionGasConsumption. -func (mr *MockCoreServiceMockRecorder) EstimateExecutionGasConsumption(ctx, sc, callerAddr interface{}, opts ...interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) EstimateExecutionGasConsumption(ctx, sc, callerAddr any, opts ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, sc, callerAddr}, opts...) + varargs := append([]any{ctx, sc, callerAddr}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateExecutionGasConsumption", reflect.TypeOf((*MockCoreService)(nil).EstimateExecutionGasConsumption), varargs...) } // EstimateExecutionGasConsumptionAt mocks base method. func (m *MockCoreService) EstimateExecutionGasConsumptionAt(ctx context.Context, sc action.Envelope, callerAddr address.Address, height uint64, opts ...protocol.SimulateOption) (uint64, []byte, error) { m.ctrl.T.Helper() - varargs := []interface{}{ctx, sc, callerAddr, height} + varargs := []any{ctx, sc, callerAddr, height} for _, a := range opts { varargs = append(varargs, a) } @@ -372,9 +377,9 @@ func (m *MockCoreService) EstimateExecutionGasConsumptionAt(ctx context.Context, } // EstimateExecutionGasConsumptionAt indicates an expected call of EstimateExecutionGasConsumptionAt. -func (mr *MockCoreServiceMockRecorder) EstimateExecutionGasConsumptionAt(ctx, sc, callerAddr, height interface{}, opts ...interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) EstimateExecutionGasConsumptionAt(ctx, sc, callerAddr, height any, opts ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, sc, callerAddr, height}, opts...) + varargs := append([]any{ctx, sc, callerAddr, height}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateExecutionGasConsumptionAt", reflect.TypeOf((*MockCoreService)(nil).EstimateExecutionGasConsumptionAt), varargs...) } @@ -388,7 +393,7 @@ func (m *MockCoreService) EstimateGasForAction(ctx context.Context, in *iotextyp } // EstimateGasForAction indicates an expected call of EstimateGasForAction. -func (mr *MockCoreServiceMockRecorder) EstimateGasForAction(ctx, in interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) EstimateGasForAction(ctx, in any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGasForAction", reflect.TypeOf((*MockCoreService)(nil).EstimateGasForAction), ctx, in) } @@ -403,7 +408,7 @@ func (m *MockCoreService) EstimateGasForNonExecution(arg0 action.Action) (uint64 } // EstimateGasForNonExecution indicates an expected call of EstimateGasForNonExecution. -func (mr *MockCoreServiceMockRecorder) EstimateGasForNonExecution(arg0 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) EstimateGasForNonExecution(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGasForNonExecution", reflect.TypeOf((*MockCoreService)(nil).EstimateGasForNonExecution), arg0) } @@ -419,7 +424,7 @@ func (m *MockCoreService) EstimateMigrateStakeGasConsumption(arg0 context.Contex } // EstimateMigrateStakeGasConsumption indicates an expected call of EstimateMigrateStakeGasConsumption. -func (mr *MockCoreServiceMockRecorder) EstimateMigrateStakeGasConsumption(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) EstimateMigrateStakeGasConsumption(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateMigrateStakeGasConsumption", reflect.TypeOf((*MockCoreService)(nil).EstimateMigrateStakeGasConsumption), arg0, arg1, arg2) } @@ -435,7 +440,7 @@ func (m *MockCoreService) EstimateMigrateStakeGasConsumptionAt(arg0 context.Cont } // EstimateMigrateStakeGasConsumptionAt indicates an expected call of EstimateMigrateStakeGasConsumptionAt. -func (mr *MockCoreServiceMockRecorder) EstimateMigrateStakeGasConsumptionAt(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) EstimateMigrateStakeGasConsumptionAt(arg0, arg1, arg2, arg3 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateMigrateStakeGasConsumptionAt", reflect.TypeOf((*MockCoreService)(nil).EstimateMigrateStakeGasConsumptionAt), arg0, arg1, arg2, arg3) } @@ -455,7 +460,7 @@ func (m *MockCoreService) FeeHistory(ctx context.Context, blocks, lastBlock uint } // FeeHistory indicates an expected call of FeeHistory. -func (mr *MockCoreServiceMockRecorder) FeeHistory(ctx, blocks, lastBlock, rewardPercentiles interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) FeeHistory(ctx, blocks, lastBlock, rewardPercentiles any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockCoreService)(nil).FeeHistory), ctx, blocks, lastBlock, rewardPercentiles) } @@ -484,7 +489,7 @@ func (m *MockCoreService) LogsInBlockByHash(filter *logfilter.LogFilter, blockHa } // LogsInBlockByHash indicates an expected call of LogsInBlockByHash. -func (mr *MockCoreServiceMockRecorder) LogsInBlockByHash(filter, blockHash interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) LogsInBlockByHash(filter, blockHash any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogsInBlockByHash", reflect.TypeOf((*MockCoreService)(nil).LogsInBlockByHash), filter, blockHash) } @@ -500,7 +505,7 @@ func (m *MockCoreService) LogsInRange(filter *logfilter.LogFilter, start, end, p } // LogsInRange indicates an expected call of LogsInRange. -func (mr *MockCoreServiceMockRecorder) LogsInRange(filter, start, end, paginationSize interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) LogsInRange(filter, start, end, paginationSize any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogsInRange", reflect.TypeOf((*MockCoreService)(nil).LogsInRange), filter, start, end, paginationSize) } @@ -515,7 +520,7 @@ func (m *MockCoreService) PendingActionByActionHash(h hash.Hash256) (*action.Sea } // PendingActionByActionHash indicates an expected call of PendingActionByActionHash. -func (mr *MockCoreServiceMockRecorder) PendingActionByActionHash(h interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) PendingActionByActionHash(h any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingActionByActionHash", reflect.TypeOf((*MockCoreService)(nil).PendingActionByActionHash), h) } @@ -530,7 +535,7 @@ func (m *MockCoreService) PendingNonce(arg0 address.Address) (uint64, error) { } // PendingNonce indicates an expected call of PendingNonce. -func (mr *MockCoreServiceMockRecorder) PendingNonce(arg0 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) PendingNonce(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingNonce", reflect.TypeOf((*MockCoreService)(nil).PendingNonce), arg0) } @@ -545,7 +550,7 @@ func (m *MockCoreService) PendingNonceAt(ctx context.Context, addr address.Addre } // PendingNonceAt indicates an expected call of PendingNonceAt. -func (mr *MockCoreServiceMockRecorder) PendingNonceAt(ctx, addr, height interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) PendingNonceAt(ctx, addr, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingNonceAt", reflect.TypeOf((*MockCoreService)(nil).PendingNonceAt), ctx, addr, height) } @@ -560,7 +565,7 @@ func (m *MockCoreService) RawBlocks(startHeight, count uint64, withReceipts, wit } // RawBlocks indicates an expected call of RawBlocks. -func (mr *MockCoreServiceMockRecorder) RawBlocks(startHeight, count, withReceipts, withTransactionLogs interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) RawBlocks(startHeight, count, withReceipts, withTransactionLogs any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RawBlocks", reflect.TypeOf((*MockCoreService)(nil).RawBlocks), startHeight, count, withReceipts, withTransactionLogs) } @@ -576,7 +581,7 @@ func (m *MockCoreService) ReadContract(ctx context.Context, callerAddr address.A } // ReadContract indicates an expected call of ReadContract. -func (mr *MockCoreServiceMockRecorder) ReadContract(ctx, callerAddr, sc interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ReadContract(ctx, callerAddr, sc any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadContract", reflect.TypeOf((*MockCoreService)(nil).ReadContract), ctx, callerAddr, sc) } @@ -591,7 +596,7 @@ func (m *MockCoreService) ReadContractStorage(ctx context.Context, addr address. } // ReadContractStorage indicates an expected call of ReadContractStorage. -func (mr *MockCoreServiceMockRecorder) ReadContractStorage(ctx, addr, key interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ReadContractStorage(ctx, addr, key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadContractStorage", reflect.TypeOf((*MockCoreService)(nil).ReadContractStorage), ctx, addr, key) } @@ -606,7 +611,7 @@ func (m *MockCoreService) ReadContractStorageAt(ctx context.Context, addr addres } // ReadContractStorageAt indicates an expected call of ReadContractStorageAt. -func (mr *MockCoreServiceMockRecorder) ReadContractStorageAt(ctx, addr, key, height interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ReadContractStorageAt(ctx, addr, key, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadContractStorageAt", reflect.TypeOf((*MockCoreService)(nil).ReadContractStorageAt), ctx, addr, key, height) } @@ -621,7 +626,7 @@ func (m *MockCoreService) ReadState(protocolID, height string, methodName []byte } // ReadState indicates an expected call of ReadState. -func (mr *MockCoreServiceMockRecorder) ReadState(protocolID, height, methodName, arguments interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ReadState(protocolID, height, methodName, arguments any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadState", reflect.TypeOf((*MockCoreService)(nil).ReadState), protocolID, height, methodName, arguments) } @@ -636,7 +641,7 @@ func (m *MockCoreService) ReceiptByActionHash(h hash.Hash256) (*action.Receipt, } // ReceiptByActionHash indicates an expected call of ReceiptByActionHash. -func (mr *MockCoreServiceMockRecorder) ReceiptByActionHash(h interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ReceiptByActionHash(h any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceiptByActionHash", reflect.TypeOf((*MockCoreService)(nil).ReceiptByActionHash), h) } @@ -650,7 +655,7 @@ func (m *MockCoreService) ReceiveBlock(blk *block.Block) error { } // ReceiveBlock indicates an expected call of ReceiveBlock. -func (mr *MockCoreServiceMockRecorder) ReceiveBlock(blk interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) ReceiveBlock(blk any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceiveBlock", reflect.TypeOf((*MockCoreService)(nil).ReceiveBlock), blk) } @@ -665,7 +670,7 @@ func (m *MockCoreService) SendAction(ctx context.Context, in *iotextypes.Action) } // SendAction indicates an expected call of SendAction. -func (mr *MockCoreServiceMockRecorder) SendAction(ctx, in interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) SendAction(ctx, in any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAction", reflect.TypeOf((*MockCoreService)(nil).SendAction), ctx, in) } @@ -699,7 +704,7 @@ func (m *MockCoreService) SimulateExecution(arg0 context.Context, arg1 address.A } // SimulateExecution indicates an expected call of SimulateExecution. -func (mr *MockCoreServiceMockRecorder) SimulateExecution(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) SimulateExecution(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SimulateExecution", reflect.TypeOf((*MockCoreService)(nil).SimulateExecution), arg0, arg1, arg2) } @@ -713,7 +718,7 @@ func (m *MockCoreService) Start(ctx context.Context) error { } // Start indicates an expected call of Start. -func (mr *MockCoreServiceMockRecorder) Start(ctx interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) Start(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockCoreService)(nil).Start), ctx) } @@ -727,7 +732,7 @@ func (m *MockCoreService) Stop(ctx context.Context) error { } // Stop indicates an expected call of Stop. -func (mr *MockCoreServiceMockRecorder) Stop(ctx interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) Stop(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockCoreService)(nil).Stop), ctx) } @@ -804,7 +809,7 @@ func (m *MockCoreService) TraceBlockByHash(ctx context.Context, blkHash string, } // TraceBlockByHash indicates an expected call of TraceBlockByHash. -func (mr *MockCoreServiceMockRecorder) TraceBlockByHash(ctx, blkHash, config interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) TraceBlockByHash(ctx, blkHash, config any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TraceBlockByHash", reflect.TypeOf((*MockCoreService)(nil).TraceBlockByHash), ctx, blkHash, config) } @@ -821,7 +826,7 @@ func (m *MockCoreService) TraceBlockByNumber(ctx context.Context, height uint64, } // TraceBlockByNumber indicates an expected call of TraceBlockByNumber. -func (mr *MockCoreServiceMockRecorder) TraceBlockByNumber(ctx, height, config interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) TraceBlockByNumber(ctx, height, config any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TraceBlockByNumber", reflect.TypeOf((*MockCoreService)(nil).TraceBlockByNumber), ctx, height, config) } @@ -838,7 +843,7 @@ func (m *MockCoreService) TraceCall(ctx context.Context, callerAddr address.Addr } // TraceCall indicates an expected call of TraceCall. -func (mr *MockCoreServiceMockRecorder) TraceCall(ctx, callerAddr, height, contractAddress, nonce, amount, gasLimit, data, config interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) TraceCall(ctx, callerAddr, height, contractAddress, nonce, amount, gasLimit, data, config any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TraceCall", reflect.TypeOf((*MockCoreService)(nil).TraceCall), ctx, callerAddr, height, contractAddress, nonce, amount, gasLimit, data, config) } @@ -855,7 +860,7 @@ func (m *MockCoreService) TraceTransaction(ctx context.Context, actHash string, } // TraceTransaction indicates an expected call of TraceTransaction. -func (mr *MockCoreServiceMockRecorder) TraceTransaction(ctx, actHash, config interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) TraceTransaction(ctx, actHash, config any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TraceTransaction", reflect.TypeOf((*MockCoreService)(nil).TraceTransaction), ctx, actHash, config) } @@ -867,7 +872,7 @@ func (m *MockCoreService) Track(ctx context.Context, start time.Time, method str } // Track indicates an expected call of Track. -func (mr *MockCoreServiceMockRecorder) Track(ctx, start, method, size, success interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) Track(ctx, start, method, size, success any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Track", reflect.TypeOf((*MockCoreService)(nil).Track), ctx, start, method, size, success) } @@ -882,7 +887,7 @@ func (m *MockCoreService) TransactionLogByActionHash(actHash string) (*iotextype } // TransactionLogByActionHash indicates an expected call of TransactionLogByActionHash. -func (mr *MockCoreServiceMockRecorder) TransactionLogByActionHash(actHash interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) TransactionLogByActionHash(actHash any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionLogByActionHash", reflect.TypeOf((*MockCoreService)(nil).TransactionLogByActionHash), actHash) } @@ -898,24 +903,24 @@ func (m *MockCoreService) TransactionLogByBlockHeight(blockHeight uint64) (*iote } // TransactionLogByBlockHeight indicates an expected call of TransactionLogByBlockHeight. -func (mr *MockCoreServiceMockRecorder) TransactionLogByBlockHeight(blockHeight interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) TransactionLogByBlockHeight(blockHeight any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionLogByBlockHeight", reflect.TypeOf((*MockCoreService)(nil).TransactionLogByBlockHeight), blockHeight) } // UnconfirmedActionsByAddress mocks base method. -func (m *MockCoreService) UnconfirmedActionsByAddress(address string, start, count uint64) ([]*iotexapi.ActionInfo, error) { +func (m *MockCoreService) UnconfirmedActionsByAddress(arg0 string, start, count uint64) ([]*iotexapi.ActionInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UnconfirmedActionsByAddress", address, start, count) + ret := m.ctrl.Call(m, "UnconfirmedActionsByAddress", arg0, start, count) ret0, _ := ret[0].([]*iotexapi.ActionInfo) ret1, _ := ret[1].(error) return ret0, ret1 } // UnconfirmedActionsByAddress indicates an expected call of UnconfirmedActionsByAddress. -func (mr *MockCoreServiceMockRecorder) UnconfirmedActionsByAddress(address, start, count interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) UnconfirmedActionsByAddress(arg0, start, count any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnconfirmedActionsByAddress", reflect.TypeOf((*MockCoreService)(nil).UnconfirmedActionsByAddress), address, start, count) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnconfirmedActionsByAddress", reflect.TypeOf((*MockCoreService)(nil).UnconfirmedActionsByAddress), arg0, start, count) } // WithHeight mocks base method. @@ -927,7 +932,7 @@ func (m *MockCoreService) WithHeight(arg0 uint64) CoreServiceReaderWithHeight { } // WithHeight indicates an expected call of WithHeight. -func (mr *MockCoreServiceMockRecorder) WithHeight(arg0 interface{}) *gomock.Call { +func (mr *MockCoreServiceMockRecorder) WithHeight(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithHeight", reflect.TypeOf((*MockCoreService)(nil).WithHeight), arg0) } @@ -936,6 +941,7 @@ func (mr *MockCoreServiceMockRecorder) WithHeight(arg0 interface{}) *gomock.Call type MockintrinsicGasCalculator struct { ctrl *gomock.Controller recorder *MockintrinsicGasCalculatorMockRecorder + isgomock struct{} } // MockintrinsicGasCalculatorMockRecorder is the mock recorder for MockintrinsicGasCalculator. diff --git a/blockindex/contractstaking/dirty_cache.go b/blockindex/contractstaking/dirty_cache.go index 88a04cd0c3..cddc22c4d3 100644 --- a/blockindex/contractstaking/dirty_cache.go +++ b/blockindex/contractstaking/dirty_cache.go @@ -11,6 +11,9 @@ import ( "github.com/pkg/errors" + "github.com/iotexproject/iotex-address/address" + + "github.com/iotexproject/iotex-core/v2/action/protocol/staking/contractstaking" "github.com/iotexproject/iotex-core/v2/db/batch" "github.com/iotexproject/iotex-core/v2/pkg/util/byteutil" ) @@ -49,6 +52,63 @@ func newContractStakingDirty(clean stakingCache) *contractStakingDirty { } } +func (dirty *contractStakingDirty) PutBucketType(contractAddr address.Address, bt *BucketType) error { + dirty.putBucketType(bt) + return nil +} + +func (dirty *contractStakingDirty) DeductBucket(contractAddr address.Address, id uint64) (*contractstaking.Bucket, error) { + bi, ok := dirty.cache.BucketInfo(id) + if !ok { + return nil, errors.Wrapf(contractstaking.ErrBucketNotExist, "bucket info %d not found", id) + } + bt, ok := dirty.cache.BucketType(bi.TypeIndex) + if !ok { + return nil, errors.New("bucket type not found") + } + return &contractstaking.Bucket{ + StakedAmount: bt.Amount, + StakedDuration: bt.Duration, + CreatedAt: bi.CreatedAt, + UnlockedAt: bi.UnlockedAt, + UnstakedAt: bi.UnstakedAt, + Candidate: bi.Delegate, + Owner: bi.Owner, + }, nil +} + +func (dirty *contractStakingDirty) DeleteBucket(contractAddr address.Address, id uint64) error { + dirty.deleteBucketInfo(id) + return nil +} + +func (dirty *contractStakingDirty) PutBucket(contractAddr address.Address, id uint64, bkt *contractstaking.Bucket) error { + bi, err := dirty.convertToBucketInfo(bkt) + if err != nil { + return err + } + dirty.addBucketInfo(id, bi) + return nil +} + +func (dirty *contractStakingDirty) convertToBucketInfo(bucket *contractstaking.Bucket) (*bucketInfo, error) { + if bucket == nil { + return nil, nil + } + tid, old := dirty.matchBucketType(bucket.StakedAmount, bucket.StakedDuration) + if old == nil { + return nil, errBucketTypeNotExist + } + return &bucketInfo{ + TypeIndex: tid, + CreatedAt: bucket.CreatedAt, + UnlockedAt: bucket.UnlockedAt, + UnstakedAt: bucket.UnstakedAt, + Delegate: bucket.Candidate, + Owner: bucket.Owner, + }, nil +} + func (dirty *contractStakingDirty) addBucketInfo(id uint64, bi *bucketInfo) { data, err := bi.Serialize() if err != nil { @@ -89,7 +149,7 @@ func (dirty *contractStakingDirty) getBucketInfo(id uint64) (*bucketInfo, bool) return dirty.cache.BucketInfo(id) } -func (dirty *contractStakingDirty) finalize() (batch.KVStoreBatch, stakingCache) { +func (dirty *contractStakingDirty) Finalize() (batch.KVStoreBatch, stakingCache) { b := dirty.finalizeBatch() return b, dirty.cache diff --git a/blockindex/contractstaking/dirty_cache_test.go b/blockindex/contractstaking/dirty_cache_test.go index 9d6736bb37..f2621f4cf1 100644 --- a/blockindex/contractstaking/dirty_cache_test.go +++ b/blockindex/contractstaking/dirty_cache_test.go @@ -147,7 +147,7 @@ func TestContractStakingDirty_finalize(t *testing.T) { require.EqualValues(0, totalCnt) // no dirty data - batcher, cache := dirty.finalize() + batcher, cache := dirty.Finalize() require.EqualValues(1, batcher.Size()) info, err := batcher.Entry(0) require.NoError(err) @@ -160,7 +160,7 @@ func TestContractStakingDirty_finalize(t *testing.T) { // added bucket type bt := &BucketType{Amount: big.NewInt(100), Duration: 100, ActivatedAt: 1} dirty.addBucketType(1, bt) - batcher, cache = dirty.finalize() + batcher, cache = dirty.Finalize() require.EqualValues(2, batcher.Size()) info, err = batcher.Entry(1) require.NoError(err) @@ -175,7 +175,7 @@ func TestContractStakingDirty_finalize(t *testing.T) { // add bucket info bi := &bucketInfo{TypeIndex: 1, CreatedAt: 2, UnlockedAt: 3, UnstakedAt: 4, Delegate: identityset.Address(1), Owner: identityset.Address(2)} dirty.addBucketInfo(1, bi) - batcher, cache = dirty.finalize() + batcher, cache = dirty.Finalize() require.EqualValues(3, batcher.Size()) info, err = batcher.Entry(2) require.NoError(err) diff --git a/blockindex/contractstaking/event_handler.go b/blockindex/contractstaking/eventprocessor.go similarity index 63% rename from blockindex/contractstaking/event_handler.go rename to blockindex/contractstaking/eventprocessor.go index abcea1db29..6d5981ec14 100644 --- a/blockindex/contractstaking/event_handler.go +++ b/blockindex/contractstaking/eventprocessor.go @@ -17,7 +17,8 @@ import ( "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/iotexproject/iotex-core/v2/action" - "github.com/iotexproject/iotex-core/v2/db/batch" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking/contractstaking" ) const ( @@ -348,10 +349,11 @@ const ( ]` ) -// contractStakingEventHandler handles events from staking contract -type contractStakingEventHandler struct { - dirty *contractStakingDirty - tokenOwner map[uint64]address.Address +// contractStakingEventProcessor handles events from staking contract +type contractStakingEventProcessor struct { + dirty staking.EventHandler + contractAddr address.Address + tokenOwner map[uint64]address.Address } var ( @@ -366,24 +368,25 @@ func init() { } } -func newContractStakingEventHandler(cache stakingCache) *contractStakingEventHandler { - dirty := newContractStakingDirty(cache) - return &contractStakingEventHandler{ - dirty: dirty, - tokenOwner: make(map[uint64]address.Address), +func newContractStakingEventProcessor(contractAddr address.Address, dirty staking.EventHandler) *contractStakingEventProcessor { + return &contractStakingEventProcessor{ + dirty: dirty, + contractAddr: contractAddr, + tokenOwner: make(map[uint64]address.Address), } } -func (eh *contractStakingEventHandler) HandleReceipts(ctx context.Context, height uint64, receipts []*action.Receipt, contractAddr string) error { +func (processor *contractStakingEventProcessor) ProcessReceipts(ctx context.Context, receipts ...*action.Receipt) error { + expectedContractAddr := processor.contractAddr.String() for _, receipt := range receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue } for _, log := range receipt.Logs() { - if log.Address != contractAddr { + if log.Address != expectedContractAddr { continue } - if err := eh.HandleEvent(ctx, height, log); err != nil { + if err := processor.HandleEvent(ctx, log); err != nil { return err } } @@ -391,7 +394,7 @@ func (eh *contractStakingEventHandler) HandleReceipts(ctx context.Context, heigh return nil } -func (eh *contractStakingEventHandler) HandleEvent(ctx context.Context, height uint64, log *action.Log) error { +func (processor *contractStakingEventProcessor) HandleEvent(ctx context.Context, log *action.Log) error { // get event abi abiEvent, err := _stakingInterface.EventByID(common.Hash(log.Topics[0])) if err != nil { @@ -407,27 +410,27 @@ func (eh *contractStakingEventHandler) HandleEvent(ctx context.Context, height u // handle different kinds of event switch abiEvent.Name { case "BucketTypeActivated": - return eh.handleBucketTypeActivatedEvent(event, height) + return processor.handleBucketTypeActivatedEvent(event, log.BlockHeight) case "BucketTypeDeactivated": - return eh.handleBucketTypeDeactivatedEvent(event, height) + return processor.handleBucketTypeDeactivatedEvent(event, log.BlockHeight) case "Staked": - return eh.handleStakedEvent(event, height) + return processor.handleStakedEvent(event, log.BlockHeight) case "Locked": - return eh.handleLockedEvent(event) + return processor.handleLockedEvent(event) case "Unlocked": - return eh.handleUnlockedEvent(event, height) + return processor.handleUnlockedEvent(event, log.BlockHeight) case "Unstaked": - return eh.handleUnstakedEvent(event, height) + return processor.handleUnstakedEvent(event, log.BlockHeight) case "Merged": - return eh.handleMergedEvent(event) + return processor.handleMergedEvent(event) case "BucketExpanded": - return eh.handleBucketExpandedEvent(event) + return processor.handleBucketExpandedEvent(event) case "DelegateChanged": - return eh.handleDelegateChangedEvent(event) + return processor.handleDelegateChangedEvent(event) case "Withdrawal": - return eh.handleWithdrawalEvent(event) + return processor.handleWithdrawalEvent(event) case "Transfer": - return eh.handleTransferEvent(event) + return processor.handleTransferEvent(event) case "Approval", "ApprovalForAll", "OwnershipTransferred", "Paused", "Unpaused": // not require handling events return nil @@ -436,11 +439,7 @@ func (eh *contractStakingEventHandler) HandleEvent(ctx context.Context, height u } } -func (eh *contractStakingEventHandler) Result() (batch.KVStoreBatch, stakingCache) { - return eh.dirty.finalize() -} - -func (eh *contractStakingEventHandler) handleTransferEvent(event eventParam) error { +func (processor *contractStakingEventProcessor) handleTransferEvent(event eventParam) error { to, err := event.IndexedFieldAddress("to") if err != nil { return err @@ -452,17 +451,21 @@ func (eh *contractStakingEventHandler) handleTransferEvent(event eventParam) err tokenID := tokenIDParam.Uint64() // cache token owner for stake event - eh.tokenOwner[tokenID] = to + processor.tokenOwner[tokenID] = to // update bucket owner if token exists - if bi, ok := eh.dirty.getBucketInfo(tokenID); ok { - bi.Owner = to - eh.dirty.updateBucketInfo(tokenID, bi) + bucket, err := processor.dirty.DeductBucket(processor.contractAddr, tokenID) + switch errors.Cause(err) { + case nil: + bucket.Owner = to + return processor.dirty.PutBucket(processor.contractAddr, tokenID, bucket) + case contractstaking.ErrBucketNotExist: + return nil + default: + return err } - - return nil } -func (eh *contractStakingEventHandler) handleBucketTypeActivatedEvent(event eventParam, height uint64) error { +func (processor *contractStakingEventProcessor) handleBucketTypeActivatedEvent(event eventParam, height uint64) error { amountParam, err := event.FieldUint256("amount") if err != nil { return err @@ -477,11 +480,10 @@ func (eh *contractStakingEventHandler) handleBucketTypeActivatedEvent(event even Duration: durationParam.Uint64(), ActivatedAt: height, } - eh.dirty.putBucketType(&bt) - return nil + return processor.dirty.PutBucketType(processor.contractAddr, &bt) } -func (eh *contractStakingEventHandler) handleBucketTypeDeactivatedEvent(event eventParam, height uint64) error { +func (processor *contractStakingEventProcessor) handleBucketTypeDeactivatedEvent(event eventParam, height uint64) error { amountParam, err := event.FieldUint256("amount") if err != nil { return err @@ -491,17 +493,16 @@ func (eh *contractStakingEventHandler) handleBucketTypeDeactivatedEvent(event ev return err } - id, bt := eh.dirty.matchBucketType(amountParam, durationParam.Uint64()) - if bt == nil { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) + bt := BucketType{ + Amount: amountParam, + Duration: durationParam.Uint64(), + ActivatedAt: maxBlockNumber, } - bt.ActivatedAt = maxBlockNumber - eh.dirty.updateBucketType(id, bt) - return nil + return processor.dirty.PutBucketType(processor.contractAddr, &bt) } -func (eh *contractStakingEventHandler) handleStakedEvent(event eventParam, height uint64) error { +func (processor *contractStakingEventProcessor) handleStakedEvent(event eventParam, height uint64) error { tokenIDParam, err := event.IndexedFieldUint256("tokenId") if err != nil { return err @@ -519,27 +520,23 @@ func (eh *contractStakingEventHandler) handleStakedEvent(event eventParam, heigh return err } - btIdx, bt := eh.dirty.matchBucketType(amountParam, durationParam.Uint64()) - if bt == nil { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) - } - owner, ok := eh.tokenOwner[tokenIDParam.Uint64()] + owner, ok := processor.tokenOwner[tokenIDParam.Uint64()] if !ok { return errors.Errorf("no owner for token id %d", tokenIDParam.Uint64()) } - bucket := bucketInfo{ - TypeIndex: btIdx, - Delegate: delegateParam, - Owner: owner, - CreatedAt: height, - UnlockedAt: maxBlockNumber, - UnstakedAt: maxBlockNumber, - } - eh.dirty.addBucketInfo(tokenIDParam.Uint64(), &bucket) - return nil + + return processor.dirty.PutBucket(processor.contractAddr, tokenIDParam.Uint64(), &contractstaking.Bucket{ + Candidate: delegateParam, + Owner: owner, + StakedAmount: amountParam, + StakedDuration: durationParam.Uint64(), + CreatedAt: height, + UnstakedAt: maxBlockNumber, + UnlockedAt: maxBlockNumber, + }) } -func (eh *contractStakingEventHandler) handleLockedEvent(event eventParam) error { +func (processor *contractStakingEventProcessor) handleLockedEvent(event eventParam) error { tokenIDParam, err := event.IndexedFieldUint256("tokenId") if err != nil { return err @@ -549,58 +546,46 @@ func (eh *contractStakingEventHandler) handleLockedEvent(event eventParam) error return err } - b, ok := eh.dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDParam.Uint64()) - } - bt, ok := eh.dirty.getBucketType(b.TypeIndex) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) - } - newBtIdx, newBt := eh.dirty.matchBucketType(bt.Amount, durationParam.Uint64()) - if newBt == nil { - return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) + bucket, err := processor.dirty.DeductBucket(processor.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err } - b.TypeIndex = newBtIdx - b.UnlockedAt = maxBlockNumber - eh.dirty.updateBucketInfo(tokenIDParam.Uint64(), b) - return nil + bucket.StakedDuration = durationParam.Uint64() + bucket.UnlockedAt = maxBlockNumber + + return processor.dirty.PutBucket(processor.contractAddr, tokenIDParam.Uint64(), bucket) } -func (eh *contractStakingEventHandler) handleUnlockedEvent(event eventParam, height uint64) error { +func (processor *contractStakingEventProcessor) handleUnlockedEvent(event eventParam, height uint64) error { tokenIDParam, err := event.IndexedFieldUint256("tokenId") if err != nil { return err } - b, ok := eh.dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDParam.Uint64()) + bucket, err := processor.dirty.DeductBucket(processor.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err } - b.UnlockedAt = height - eh.dirty.updateBucketInfo(tokenIDParam.Uint64(), b) - - return nil + bucket.UnlockedAt = height + return processor.dirty.PutBucket(processor.contractAddr, tokenIDParam.Uint64(), bucket) } -func (eh *contractStakingEventHandler) handleUnstakedEvent(event eventParam, height uint64) error { +func (processor *contractStakingEventProcessor) handleUnstakedEvent(event eventParam, height uint64) error { tokenIDParam, err := event.IndexedFieldUint256("tokenId") if err != nil { return err } - b, ok := eh.dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDParam.Uint64()) + bucket, err := processor.dirty.DeductBucket(processor.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err } - b.UnstakedAt = height - eh.dirty.updateBucketInfo(tokenIDParam.Uint64(), b) - - return nil + bucket.UnstakedAt = height + return processor.dirty.PutBucket(processor.contractAddr, tokenIDParam.Uint64(), bucket) } -func (eh *contractStakingEventHandler) handleMergedEvent(event eventParam) error { +func (processor *contractStakingEventProcessor) handleMergedEvent(event eventParam) error { tokenIDsParam, err := event.FieldUint256Slice("tokenIds") if err != nil { return err @@ -615,25 +600,22 @@ func (eh *contractStakingEventHandler) handleMergedEvent(event eventParam) error } // merge to the first bucket - btIdx, bt := eh.dirty.matchBucketType(amountParam, durationParam.Uint64()) - if bt == nil { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) - } - b, ok := eh.dirty.getBucketInfo(tokenIDsParam[0].Uint64()) - if !ok { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDsParam[0].Uint64()) + bucket, err := processor.dirty.DeductBucket(processor.contractAddr, tokenIDsParam[0].Uint64()) + if err != nil { + return err } - b.TypeIndex = btIdx - b.UnlockedAt = maxBlockNumber + bucket.StakedAmount = amountParam + bucket.StakedDuration = durationParam.Uint64() + bucket.UnlockedAt = maxBlockNumber for i := 1; i < len(tokenIDsParam); i++ { - eh.dirty.deleteBucketInfo(tokenIDsParam[i].Uint64()) + if err := processor.dirty.DeleteBucket(processor.contractAddr, tokenIDsParam[i].Uint64()); err != nil { + return err + } } - eh.dirty.updateBucketInfo(tokenIDsParam[0].Uint64(), b) - - return nil + return processor.dirty.PutBucket(processor.contractAddr, tokenIDsParam[0].Uint64(), bucket) } -func (eh *contractStakingEventHandler) handleBucketExpandedEvent(event eventParam) error { +func (processor *contractStakingEventProcessor) handleBucketExpandedEvent(event eventParam) error { tokenIDParam, err := event.IndexedFieldUint256("tokenId") if err != nil { return err @@ -647,21 +629,17 @@ func (eh *contractStakingEventHandler) handleBucketExpandedEvent(event eventPara return err } - b, ok := eh.dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDParam.Uint64()) - } - newBtIdx, newBucketType := eh.dirty.matchBucketType(amountParam, durationParam.Uint64()) - if newBucketType == nil { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) + bucket, err := processor.dirty.DeductBucket(processor.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err } - b.TypeIndex = newBtIdx - eh.dirty.updateBucketInfo(tokenIDParam.Uint64(), b) + bucket.StakedAmount = amountParam + bucket.StakedDuration = durationParam.Uint64() - return nil + return processor.dirty.PutBucket(processor.contractAddr, tokenIDParam.Uint64(), bucket) } -func (eh *contractStakingEventHandler) handleDelegateChangedEvent(event eventParam) error { +func (processor *contractStakingEventProcessor) handleDelegateChangedEvent(event eventParam) error { tokenIDParam, err := event.IndexedFieldUint256("tokenId") if err != nil { return err @@ -671,22 +649,19 @@ func (eh *contractStakingEventHandler) handleDelegateChangedEvent(event eventPar return err } - b, ok := eh.dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { + bucket, err := processor.dirty.DeductBucket(processor.contractAddr, tokenIDParam.Uint64()) + if err != nil { return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDParam.Uint64()) } - b.Delegate = delegateParam - eh.dirty.updateBucketInfo(tokenIDParam.Uint64(), b) + bucket.Candidate = delegateParam - return nil + return processor.dirty.PutBucket(processor.contractAddr, tokenIDParam.Uint64(), bucket) } -func (eh *contractStakingEventHandler) handleWithdrawalEvent(event eventParam) error { +func (processor *contractStakingEventProcessor) handleWithdrawalEvent(event eventParam) error { tokenIDParam, err := event.IndexedFieldUint256("tokenId") if err != nil { return err } - eh.dirty.deleteBucketInfo(tokenIDParam.Uint64()) - - return nil + return processor.dirty.DeleteBucket(processor.contractAddr, tokenIDParam.Uint64()) } diff --git a/blockindex/contractstaking/indexer.go b/blockindex/contractstaking/indexer.go index 7e21fe5bf2..b6fe9c2616 100644 --- a/blockindex/contractstaking/indexer.go +++ b/blockindex/contractstaking/indexer.go @@ -85,6 +85,14 @@ func (s *Indexer) Start(ctx context.Context) error { return s.start(ctx) } +// CreateEventProcessor creates a new event processor for contract staking +func (s *Indexer) CreateEventProcessor(ctx context.Context, handler staking.EventHandler) staking.EventProcessor { + return newContractStakingEventProcessor( + s.contractAddr, + handler, + ) +} + // LoadStakeView loads the contract stake view func (s *Indexer) LoadStakeView(ctx context.Context, sr protocol.StateReader) (staking.ContractStakeView, error) { if !s.IsReady() { @@ -382,8 +390,9 @@ func (s *Indexer) PutBlock(ctx context.Context, blk *block.Block) error { if blk.Height() > expectHeight { return errors.Errorf("invalid block height %d, expect %d", blk.Height(), expectHeight) } - handler := newContractStakingEventHandler(cache) - if err := handler.HandleReceipts(ctx, blk.Height(), blk.Receipts, s.contractAddr.String()); err != nil { + handler := newContractStakingDirty(cache) + processor := newContractStakingEventProcessor(s.contractAddr, handler) + if err := processor.ProcessReceipts(ctx, blk.Receipts...); err != nil { return errors.Wrapf(err, "failed to handle receipts at height %d", blk.Height()) } s.mu.Lock() @@ -395,8 +404,8 @@ func (s *Indexer) PutBlock(ctx context.Context, blk *block.Block) error { return nil } -func (s *Indexer) commit(ctx context.Context, handler *contractStakingEventHandler, height uint64) error { - batch, delta := handler.Result() +func (s *Indexer) commit(ctx context.Context, handler *contractStakingDirty, height uint64) error { + batch, delta := handler.Finalize() cache, err := delta.Commit(ctx, s.contractAddr, nil) if err != nil { return errors.Wrapf(err, "failed to commit delta") diff --git a/blockindex/contractstaking/indexer_test.go b/blockindex/contractstaking/indexer_test.go index fcad0fa702..6725b7e23a 100644 --- a/blockindex/contractstaking/indexer_test.go +++ b/blockindex/contractstaking/indexer_test.go @@ -103,12 +103,15 @@ func TestContractStakingIndexerLoadCache(t *testing.T) { // create a stake height := uint64(1) startHeight := uint64(1) - handler := newContractStakingEventHandler(indexer.cache) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) + dirty := newContractStakingDirty(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) activateBucketType(r, handler, 10, 100, height) owner := identityset.Address(0) delegate := identityset.Address(1) stake(r, handler, owner, delegate, 1, 10, 100, height) - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) buckets, err := indexer.Buckets(height) r.NoError(err) @@ -168,12 +171,12 @@ func TestContractStakingIndexerDirty(t *testing.T) { // before commit dirty, the cache should be empty height := uint64(1) - handler := newContractStakingEventHandler(indexer.cache) + dirty := newContractStakingDirty(indexer.cache) gotHeight, err := indexer.Height() r.NoError(err) r.EqualValues(0, gotHeight) // after commit dirty, the cache should be updated - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) gotHeight, err = indexer.Height() r.NoError(err) @@ -198,6 +201,8 @@ func TestContractStakingIndexerThreadSafe(t *testing.T) { }) r.NoError(err) r.NoError(indexer.Start(context.Background())) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) wait := sync.WaitGroup{} wait.Add(6) @@ -228,16 +233,17 @@ func TestContractStakingIndexerThreadSafe(t *testing.T) { defer wait.Done() // activate bucket type indexer.mu.Lock() - handler := newContractStakingEventHandler(indexer.cache) + dirty := newContractStakingDirty(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) activateBucketType(r, handler, 10, 100, 1) - r.NoError(indexer.commit(context.Background(), handler, 1)) + r.NoError(indexer.commit(context.Background(), dirty, 1)) indexer.mu.Unlock() for i := 2; i < 1000; i++ { height := uint64(i) indexer.mu.Lock() - handler := newContractStakingEventHandler(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) stake(r, handler, owner, delegate, int64(i), 10, 100, height) - err := indexer.commit(context.Background(), handler, height) + err := indexer.commit(context.Background(), dirty, height) r.NoError(err) indexer.mu.Unlock() } @@ -263,6 +269,8 @@ func TestContractStakingIndexerBucketType(t *testing.T) { }) r.NoError(err) r.NoError(indexer.Start(context.Background())) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) // activate bucketTypeData := [][2]int64{ @@ -282,11 +290,12 @@ func TestContractStakingIndexerBucketType(t *testing.T) { } height := uint64(1) - handler := newContractStakingEventHandler(indexer.cache) + dirty := newContractStakingDirty(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) for _, data := range bucketTypeData { activateBucketType(r, handler, data[0], data[1], height) } - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) bucketTypes, err := indexer.BucketTypes(height) r.NoError(err) @@ -297,12 +306,12 @@ func TestContractStakingIndexerBucketType(t *testing.T) { } // deactivate height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) for i := 0; i < 2; i++ { data := bucketTypeData[i] deactivateBucketType(r, handler, data[0], data[1], height) } - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) bucketTypes, err = indexer.BucketTypes(height) r.NoError(err) @@ -313,12 +322,12 @@ func TestContractStakingIndexerBucketType(t *testing.T) { } // reactivate height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) for i := 0; i < 2; i++ { data := bucketTypeData[i] activateBucketType(r, handler, data[0], data[1], height) } - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) bucketTypes, err = indexer.BucketTypes(height) r.NoError(err) @@ -351,6 +360,8 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { }) r.NoError(err) r.NoError(indexer.Start(context.Background())) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) // init bucket type bucketTypeData := [][2]int64{ @@ -360,11 +371,12 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { {20, 100}, } height := uint64(1) - handler := newContractStakingEventHandler(indexer.cache) + dirty := newContractStakingDirty(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) for _, data := range bucketTypeData { activateBucketType(r, handler, data[0], data[1], height) } - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) ctx := protocol.WithFeatureCtx(protocol.WithBlockCtx(genesis.WithGenesisContext(context.Background(), genesis.TestDefault()), protocol.BlockCtx{BlockHeight: 1})) @@ -373,10 +385,10 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { delegate := identityset.Address(1) height++ createHeight := height - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) stake(r, handler, owner, delegate, 1, 10, 100, height) r.NoError(err) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err := indexer.Bucket(1, height) r.NoError(err) r.True(ok) @@ -400,9 +412,9 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { // transfer newOwner := identityset.Address(2) height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) transfer(r, handler, newOwner, int64(bucket.Index)) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err = indexer.Bucket(bucket.Index, height) r.NoError(err) r.True(ok) @@ -410,9 +422,9 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { // unlock height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) unlock(r, handler, int64(bucket.Index), height) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err = indexer.Bucket(bucket.Index, height) r.NoError(err) r.True(ok) @@ -434,9 +446,9 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { // lock again height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) lock(r, handler, int64(bucket.Index), int64(10)) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err = indexer.Bucket(bucket.Index, height) r.NoError(err) r.True(ok) @@ -458,11 +470,11 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { // unstake height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) unlock(r, handler, int64(bucket.Index), height) t.Log("unstake bucket", bucket.Index, "at height", height) unstake(r, handler, int64(bucket.Index), height) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err = indexer.Bucket(bucket.Index, height) r.NoError(err) r.True(ok) @@ -484,9 +496,9 @@ func TestContractStakingIndexerBucketInfo(t *testing.T) { // withdraw height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) withdraw(r, handler, int64(bucket.Index)) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err = indexer.Bucket(bucket.Index, height) r.NoError(err) r.False(ok) @@ -514,6 +526,8 @@ func TestContractStakingIndexerChangeBucketType(t *testing.T) { }) r.NoError(err) r.NoError(indexer.Start(context.Background())) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) // init bucket type bucketTypeData := [][2]int64{ @@ -523,27 +537,28 @@ func TestContractStakingIndexerChangeBucketType(t *testing.T) { {20, 100}, } height := uint64(1) - handler := newContractStakingEventHandler(indexer.cache) + dirty := newContractStakingDirty(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) for _, data := range bucketTypeData { activateBucketType(r, handler, data[0], data[1], height) } - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) t.Run("expand bucket type", func(t *testing.T) { owner := identityset.Address(0) delegate := identityset.Address(1) height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) stake(r, handler, owner, delegate, 1, 10, 100, height) r.NoError(err) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err := indexer.Bucket(1, height) r.NoError(err) r.True(ok) expandBucketType(r, handler, int64(bucket.Index), 20, 100) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bucket, ok, err = indexer.Bucket(bucket.Index, height) r.NoError(err) r.True(ok) @@ -568,6 +583,8 @@ func TestContractStakingIndexerReadBuckets(t *testing.T) { }) r.NoError(err) r.NoError(indexer.Start(context.Background())) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) // init bucket type bucketTypeData := [][2]int64{ @@ -577,11 +594,12 @@ func TestContractStakingIndexerReadBuckets(t *testing.T) { {20, 100}, } height := uint64(1) - handler := newContractStakingEventHandler(indexer.cache) + dirty := newContractStakingDirty(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) for _, data := range bucketTypeData { activateBucketType(r, handler, data[0], data[1], height) } - err = indexer.commit(context.Background(), handler, height) + err = indexer.commit(context.Background(), dirty, height) r.NoError(err) // stake @@ -597,12 +615,12 @@ func TestContractStakingIndexerReadBuckets(t *testing.T) { {1, 3, 20, 100}, } height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) for i, data := range stakeData { stake(r, handler, identityset.Address(data.owner), identityset.Address(data.delegate), int64(i+1), int64(data.amount), int64(data.duration), height) } r.NoError(err) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) t.Run("Buckets", func(t *testing.T) { buckets, err := indexer.Buckets(height) @@ -673,10 +691,13 @@ func TestContractStakingIndexerCacheClean(t *testing.T) { }) r.NoError(err) r.NoError(indexer.Start(context.Background())) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) // init bucket type height := uint64(1) - handler := newContractStakingEventHandler(newWrappedCache(indexer.cache)) + dirty := newContractStakingDirty(newWrappedCache(indexer.cache)) + handler := newContractStakingEventProcessor(contractAddr, dirty) activateBucketType(r, handler, 10, 10, height) activateBucketType(r, handler, 20, 20, height) // create bucket @@ -693,7 +714,7 @@ func TestContractStakingIndexerCacheClean(t *testing.T) { r.Len(ids, 0) r.Len(bts, 0) r.Len(bis, 0) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) abt = indexer.cache.ActiveBucketTypes() r.Len(abt, 2) ids, bts, bis = indexer.cache.Buckets() @@ -702,7 +723,8 @@ func TestContractStakingIndexerCacheClean(t *testing.T) { r.Len(bis, 4) height++ - handler = newContractStakingEventHandler(newWrappedCache(indexer.cache)) + dirty = newContractStakingDirty(newWrappedCache(indexer.cache)) + handler = newContractStakingEventProcessor(contractAddr, dirty) changeDelegate(r, handler, delegate1, 3) transfer(r, handler, delegate1, 1) bt, ok, err := indexer.Bucket(3, height-1) @@ -713,7 +735,7 @@ func TestContractStakingIndexerCacheClean(t *testing.T) { r.NoError(err) r.True(ok) r.Equal(owner.String(), bt.Owner.String()) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) bt, ok, err = indexer.Bucket(3, height) r.NoError(err) r.True(ok) @@ -740,11 +762,14 @@ func TestContractStakingIndexerVotes(t *testing.T) { }) r.NoError(err) r.NoError(indexer.Start(context.Background())) + contractAddr, err := address.FromString(_testStakingContractAddress) + r.NoError(err) ctx := protocol.WithFeatureCtx(protocol.WithBlockCtx(genesis.WithGenesisContext(context.Background(), genesis.TestDefault()), protocol.BlockCtx{BlockHeight: 1})) // init bucket type height := uint64(1) - handler := newContractStakingEventHandler(indexer.cache) + dirty := newContractStakingDirty(indexer.cache) + handler := newContractStakingEventProcessor(contractAddr, dirty) activateBucketType(r, handler, 10, 10, height) activateBucketType(r, handler, 20, 20, height) activateBucketType(r, handler, 30, 20, height) @@ -757,7 +782,7 @@ func TestContractStakingIndexerVotes(t *testing.T) { stake(r, handler, owner, delegate1, 2, 20, 20, height) stake(r, handler, owner, delegate2, 3, 20, 20, height) stake(r, handler, owner, delegate2, 4, 20, 20, height) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err := indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(30, votes.Uint64()) @@ -769,9 +794,9 @@ func TestContractStakingIndexerVotes(t *testing.T) { // change delegate bucket 3 to delegate1 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) changeDelegate(r, handler, delegate1, 3) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(50, votes.Uint64()) @@ -781,10 +806,10 @@ func TestContractStakingIndexerVotes(t *testing.T) { // unlock bucket 1 & 4 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) unlock(r, handler, 1, height) unlock(r, handler, 4, height) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(50, votes.Uint64()) @@ -794,10 +819,10 @@ func TestContractStakingIndexerVotes(t *testing.T) { // unstake bucket 1 & lock 4 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) unstake(r, handler, 1, height) lock(r, handler, 4, 20) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(uint64(40), votes.Uint64()) @@ -807,9 +832,9 @@ func TestContractStakingIndexerVotes(t *testing.T) { // expand bucket 2 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) expandBucketType(r, handler, 2, 30, 20) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(50, votes.Uint64()) @@ -819,9 +844,9 @@ func TestContractStakingIndexerVotes(t *testing.T) { // transfer bucket 4 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) transfer(r, handler, delegate2, 4) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(50, votes.Uint64()) @@ -831,11 +856,11 @@ func TestContractStakingIndexerVotes(t *testing.T) { // create bucket 5, 6, 7 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) stake(r, handler, owner, delegate2, 5, 20, 20, height) stake(r, handler, owner, delegate2, 6, 20, 20, height) stake(r, handler, owner, delegate2, 7, 20, 20, height) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(50, votes.Uint64()) @@ -845,9 +870,9 @@ func TestContractStakingIndexerVotes(t *testing.T) { // merge bucket 5, 6, 7 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) mergeBuckets(r, handler, []int64{5, 6, 7}, 60, 20) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(50, votes.Uint64()) @@ -857,10 +882,10 @@ func TestContractStakingIndexerVotes(t *testing.T) { // unlock & unstake 5 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) unlock(r, handler, 5, height) unstake(r, handler, 5, height) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(50, votes.Uint64()) @@ -870,12 +895,12 @@ func TestContractStakingIndexerVotes(t *testing.T) { // create & merge bucket 8, 9, 10 height++ - handler = newContractStakingEventHandler(indexer.cache) + handler = newContractStakingEventProcessor(contractAddr, dirty) stake(r, handler, owner, delegate1, 8, 20, 20, height) stake(r, handler, owner, delegate2, 9, 20, 20, height) stake(r, handler, owner, delegate2, 10, 20, 20, height) mergeBuckets(r, handler, []int64{8, 9, 10}, 60, 20) - r.NoError(indexer.commit(context.Background(), handler, height)) + r.NoError(indexer.commit(context.Background(), dirty, height)) votes, err = indexer.CandidateVotes(ctx, delegate1, height) r.NoError(err) r.EqualValues(110, votes.Uint64()) @@ -1180,7 +1205,7 @@ func BenchmarkIndexer_PutBlockBeforeContractHeight(b *testing.B) { } } -func activateBucketType(r *require.Assertions, handler *contractStakingEventHandler, amount, duration int64, height uint64) { +func activateBucketType(r *require.Assertions, handler *contractStakingEventProcessor, amount, duration int64, height uint64) { err := handler.handleBucketTypeActivatedEvent(eventParam{ "amount": big.NewInt(amount), "duration": big.NewInt(duration), @@ -1188,7 +1213,7 @@ func activateBucketType(r *require.Assertions, handler *contractStakingEventHand r.NoError(err) } -func deactivateBucketType(r *require.Assertions, handler *contractStakingEventHandler, amount, duration int64, height uint64) { +func deactivateBucketType(r *require.Assertions, handler *contractStakingEventProcessor, amount, duration int64, height uint64) { err := handler.handleBucketTypeDeactivatedEvent(eventParam{ "amount": big.NewInt(amount), "duration": big.NewInt(duration), @@ -1196,7 +1221,7 @@ func deactivateBucketType(r *require.Assertions, handler *contractStakingEventHa r.NoError(err) } -func stake(r *require.Assertions, handler *contractStakingEventHandler, owner, candidate address.Address, token, amount, duration int64, height uint64) { +func stake(r *require.Assertions, handler *contractStakingEventProcessor, owner, candidate address.Address, token, amount, duration int64, height uint64) { err := handler.handleTransferEvent(eventParam{ "to": common.BytesToAddress(owner.Bytes()), "tokenId": big.NewInt(token), @@ -1211,14 +1236,14 @@ func stake(r *require.Assertions, handler *contractStakingEventHandler, owner, c r.NoError(err) } -func unlock(r *require.Assertions, handler *contractStakingEventHandler, token int64, height uint64) { +func unlock(r *require.Assertions, handler *contractStakingEventProcessor, token int64, height uint64) { err := handler.handleUnlockedEvent(eventParam{ "tokenId": big.NewInt(token), }, height) r.NoError(err) } -func lock(r *require.Assertions, handler *contractStakingEventHandler, token, duration int64) { +func lock(r *require.Assertions, handler *contractStakingEventProcessor, token, duration int64) { err := handler.handleLockedEvent(eventParam{ "tokenId": big.NewInt(token), "duration": big.NewInt(duration), @@ -1226,21 +1251,21 @@ func lock(r *require.Assertions, handler *contractStakingEventHandler, token, du r.NoError(err) } -func unstake(r *require.Assertions, handler *contractStakingEventHandler, token int64, height uint64) { +func unstake(r *require.Assertions, handler *contractStakingEventProcessor, token int64, height uint64) { err := handler.handleUnstakedEvent(eventParam{ "tokenId": big.NewInt(token), }, height) r.NoError(err) } -func withdraw(r *require.Assertions, handler *contractStakingEventHandler, token int64) { +func withdraw(r *require.Assertions, handler *contractStakingEventProcessor, token int64) { err := handler.handleWithdrawalEvent(eventParam{ "tokenId": big.NewInt(token), }) r.NoError(err) } -func expandBucketType(r *require.Assertions, handler *contractStakingEventHandler, token, amount, duration int64) { +func expandBucketType(r *require.Assertions, handler *contractStakingEventProcessor, token, amount, duration int64) { err := handler.handleBucketExpandedEvent(eventParam{ "tokenId": big.NewInt(token), "amount": big.NewInt(amount), @@ -1249,7 +1274,7 @@ func expandBucketType(r *require.Assertions, handler *contractStakingEventHandle r.NoError(err) } -func transfer(r *require.Assertions, handler *contractStakingEventHandler, owner address.Address, token int64) { +func transfer(r *require.Assertions, handler *contractStakingEventProcessor, owner address.Address, token int64) { err := handler.handleTransferEvent(eventParam{ "to": common.BytesToAddress(owner.Bytes()), "tokenId": big.NewInt(token), @@ -1257,7 +1282,7 @@ func transfer(r *require.Assertions, handler *contractStakingEventHandler, owner r.NoError(err) } -func changeDelegate(r *require.Assertions, handler *contractStakingEventHandler, delegate address.Address, token int64) { +func changeDelegate(r *require.Assertions, handler *contractStakingEventProcessor, delegate address.Address, token int64) { err := handler.handleDelegateChangedEvent(eventParam{ "newDelegate": common.BytesToAddress(delegate.Bytes()), "tokenId": big.NewInt(token), @@ -1265,7 +1290,7 @@ func changeDelegate(r *require.Assertions, handler *contractStakingEventHandler, r.NoError(err) } -func mergeBuckets(r *require.Assertions, handler *contractStakingEventHandler, tokenIds []int64, amount, duration int64) { +func mergeBuckets(r *require.Assertions, handler *contractStakingEventProcessor, tokenIds []int64, amount, duration int64) { tokens := make([]*big.Int, len(tokenIds)) for i, token := range tokenIds { tokens[i] = big.NewInt(token) diff --git a/blockindex/contractstaking/stakeview.go b/blockindex/contractstaking/stakeview.go index 6de2803567..f9dd38516c 100644 --- a/blockindex/contractstaking/stakeview.go +++ b/blockindex/contractstaking/stakeview.go @@ -5,7 +5,6 @@ import ( "slices" "github.com/iotexproject/iotex-address/address" - "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" "github.com/iotexproject/iotex-core/v2/action" @@ -57,7 +56,7 @@ func (s *stakeView) IsDirty() bool { return s.cache.IsDirty() } -func (s *stakeView) WriteBuckets(sm protocol.StateManager) error { +func (s *stakeView) Migrate(sm protocol.StateManager) error { ids, types, infos := s.cache.Buckets() cssm := contractstaking.NewContractStakingStateManager(sm) bucketMap := make(map[uint64]*bucketInfo, len(ids)) @@ -106,23 +105,13 @@ func (s *stakeView) CreatePreStates(ctx context.Context) error { } func (s *stakeView) Handle(ctx context.Context, receipt *action.Receipt) error { - blkCtx := protocol.MustGetBlockCtx(ctx) // new event handler for this receipt - handler := newContractStakingEventHandler(newWrappedCache(s.cache)) - - // handle events of receipt - if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { - return nil - } - for _, log := range receipt.Logs() { - if log.Address != s.contractAddr.String() { - continue - } - if err := handler.HandleEvent(ctx, blkCtx.BlockHeight, log); err != nil { - return err - } + handler := newContractStakingDirty(newWrappedCache(s.cache)) + processor := newContractStakingEventProcessor(s.contractAddr, handler) + if err := processor.ProcessReceipts(ctx, receipt); err != nil { + return err } - _, delta := handler.Result() + _, delta := handler.Finalize() s.cache = delta return nil @@ -151,11 +140,12 @@ func (s *stakeView) AddBlockReceipts(ctx context.Context, receipts []*action.Rec return errors.Errorf("invalid block height %d, expect %d", height, expectHeight) } - handler := newContractStakingEventHandler(newWrappedCache(s.cache)) - if err := handler.HandleReceipts(ctx, height, receipts, s.contractAddr.String()); err != nil { + handler := newContractStakingDirty(newWrappedCache(s.cache)) + processor := newContractStakingEventProcessor(s.contractAddr, handler) + if err := processor.ProcessReceipts(ctx, receipts...); err != nil { return err } - _, delta := handler.Result() + _, delta := handler.Finalize() s.cache = delta s.height = height return nil diff --git a/systemcontractindex/stakingindex/event_handler.go b/systemcontractindex/stakingindex/event_handler.go index 8b383b205a..abad132189 100644 --- a/systemcontractindex/stakingindex/event_handler.go +++ b/systemcontractindex/stakingindex/event_handler.go @@ -1,293 +1,40 @@ package stakingindex import ( - "context" - _ "embed" - "math" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "go.uber.org/zap" "github.com/iotexproject/iotex-address/address" - "github.com/iotexproject/iotex-proto/golang/iotextypes" - - "github.com/iotexproject/iotex-core/v2/action" - "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking/contractstaking" "github.com/iotexproject/iotex-core/v2/db/batch" - "github.com/iotexproject/iotex-core/v2/pkg/log" - "github.com/iotexproject/iotex-core/v2/pkg/util/abiutil" "github.com/iotexproject/iotex-core/v2/pkg/util/byteutil" ) -const ( - maxStakingNumber uint64 = math.MaxUint64 -) - -var ( - //go:embed staking_contract_abi_v3.json - stakingContractABIJSON string - // StakingContractABI is the abi of staking contract - StakingContractABI abi.ABI - - // ErrBucketNotExist is the error when bucket does not exist - ErrBucketNotExist = errors.New("bucket does not exist") -) - -type eventHandler struct { - stakingBucketNS string - dirty indexerCache // dirty cache, a view for current block - delta batch.KVStoreBatch // delta for db to store buckets of current block - tokenOwner map[uint64]address.Address - // context for event handler - blockCtx protocol.BlockCtx - timestamped bool - muted bool -} - -func init() { - var err error - StakingContractABI, err = abi.JSON(strings.NewReader(stakingContractABIJSON)) - if err != nil { - panic(err) +type ( + eventHandler struct { + stakingBucketNS string + dirty indexerCache // dirty cache, a view for current block + delta batch.KVStoreBatch // delta for db to store buckets of current block } -} +) -func newEventHandler(bucketNS string, dirty indexerCache, blkCtx protocol.BlockCtx, timestamped, muted bool) *eventHandler { +func newEventHandler(bucketNS string, dirty indexerCache) *eventHandler { return &eventHandler{ stakingBucketNS: bucketNS, dirty: dirty, delta: batch.NewBatch(), - tokenOwner: make(map[uint64]address.Address), - blockCtx: blkCtx, - timestamped: timestamped, - muted: muted, } } -func (eh *eventHandler) HandleStakedEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - delegateParam, err := event.FieldByIDAddress(1) - if err != nil { - return err - } - amountParam, err := event.FieldByIDUint256(2) - if err != nil { - return err - } - durationParam, err := event.FieldByIDUint256(3) - if err != nil { - return err - } - owner, ok := eh.tokenOwner[tokenIDParam.Uint64()] - if !ok { - return errors.Errorf("no owner for token id %d", tokenIDParam.Uint64()) - } - createdAt := eh.blockCtx.BlockHeight - if eh.timestamped { - createdAt = uint64(eh.blockCtx.BlockTimeStamp.Unix()) - } - bucket := &Bucket{ - Candidate: delegateParam, - Owner: owner, - StakedAmount: amountParam, - StakedDuration: durationParam.Uint64(), - CreatedAt: createdAt, - UnlockedAt: maxStakingNumber, - UnstakedAt: maxStakingNumber, - IsTimestampBased: eh.timestamped, - Muted: eh.muted, - } - eh.putBucket(tokenIDParam.Uint64(), bucket) - return nil +func (eh *eventHandler) PutBucketType(_ address.Address, bt *contractstaking.BucketType) error { + return errors.New("not implemented") } -func (eh *eventHandler) HandleLockedEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - durationParam, err := event.FieldByIDUint256(1) - if err != nil { - return err - } - - bkt := eh.dirty.Bucket(tokenIDParam.Uint64()) +func (eh *eventHandler) DeductBucket(_ address.Address, id uint64) (*Bucket, error) { + bkt := eh.dirty.Bucket(id) if bkt == nil { - return errors.Errorf("no bucket for token id %d", tokenIDParam.Uint64()) - } - bkt.StakedDuration = durationParam.Uint64() - bkt.UnlockedAt = maxStakingNumber - bkt.Muted = eh.muted - eh.putBucket(tokenIDParam.Uint64(), bkt) - return nil -} - -func (eh *eventHandler) HandleUnlockedEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - - bkt := eh.dirty.Bucket(tokenIDParam.Uint64()) - if bkt == nil { - return errors.Errorf("no bucket for token id %d", tokenIDParam.Uint64()) - } - bkt.UnlockedAt = eh.blockCtx.BlockHeight - if eh.timestamped { - bkt.UnlockedAt = uint64(eh.blockCtx.BlockTimeStamp.Unix()) - } - eh.putBucket(tokenIDParam.Uint64(), bkt) - return nil -} - -func (eh *eventHandler) HandleUnstakedEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - - bkt := eh.dirty.Bucket(tokenIDParam.Uint64()) - if bkt == nil { - return errors.Errorf("no bucket for token id %d", tokenIDParam.Uint64()) - } - bkt.UnstakedAt = eh.blockCtx.BlockHeight - if eh.timestamped { - bkt.UnstakedAt = uint64(eh.blockCtx.BlockTimeStamp.Unix()) - } - eh.putBucket(tokenIDParam.Uint64(), bkt) - return nil -} - -func (eh *eventHandler) HandleDelegateChangedEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - delegateParam, err := event.FieldByIDAddress(1) - if err != nil { - return err - } - - bkt := eh.dirty.Bucket(tokenIDParam.Uint64()) - if bkt == nil { - return errors.Errorf("no bucket for token id %d", tokenIDParam.Uint64()) - } - bkt.Candidate = delegateParam - eh.putBucket(tokenIDParam.Uint64(), bkt) - return nil -} - -func (eh *eventHandler) HandleWithdrawalEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - - eh.delBucket(tokenIDParam.Uint64()) - return nil -} - -func (eh *eventHandler) HandleTransferEvent(event *abiutil.EventParam) error { - to, err := event.FieldByIDAddress(1) - if err != nil { - return err - } - tokenIDParam, err := event.FieldByIDUint256(2) - if err != nil { - return err - } - - tokenID := tokenIDParam.Uint64() - // cache token owner for stake event - eh.tokenOwner[tokenID] = to - // update bucket owner if token exists - bkt := eh.dirty.Bucket(tokenID) - if bkt != nil { - bkt.Owner = to - eh.putBucket(tokenID, bkt) - } - return nil -} - -func (eh *eventHandler) HandleMergedEvent(event *abiutil.EventParam) error { - tokenIDsParam, err := event.FieldByIDUint256Slice(0) - if err != nil { - return err - } - amountParam, err := event.FieldByIDUint256(1) - if err != nil { - return err - } - durationParam, err := event.FieldByIDUint256(2) - if err != nil { - return err + return nil, errors.Wrapf(contractstaking.ErrBucketNotExist, "token id %d", id) } - - // merge to the first bucket - b := eh.dirty.Bucket(tokenIDsParam[0].Uint64()) - if b == nil { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDsParam[0].Uint64()) - } - b.StakedAmount = amountParam - b.StakedDuration = durationParam.Uint64() - b.UnlockedAt = maxStakingNumber - b.Muted = eh.muted - for i := 1; i < len(tokenIDsParam); i++ { - eh.delBucket(tokenIDsParam[i].Uint64()) - } - eh.putBucket(tokenIDsParam[0].Uint64(), b) - return nil -} - -func (eh *eventHandler) HandleBucketExpandedEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - amountParam, err := event.FieldByIDUint256(1) - if err != nil { - return err - } - durationParam, err := event.FieldByIDUint256(2) - if err != nil { - return err - } - - b := eh.dirty.Bucket(tokenIDParam.Uint64()) - if b == nil { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDParam.Uint64()) - } - b.StakedAmount = amountParam - b.StakedDuration = durationParam.Uint64() - b.Muted = eh.muted - eh.putBucket(tokenIDParam.Uint64(), b) - return nil -} - -func (eh *eventHandler) HandleDonatedEvent(event *abiutil.EventParam) error { - tokenIDParam, err := event.FieldByIDUint256(0) - if err != nil { - return err - } - amountParam, err := event.FieldByIDUint256(2) - if err != nil { - return err - } - - b := eh.dirty.Bucket(tokenIDParam.Uint64()) - if b == nil { - return errors.Wrapf(ErrBucketNotExist, "token id %d", tokenIDParam.Uint64()) - } - b.StakedAmount.Sub(b.StakedAmount, amountParam) - b.Muted = eh.muted - eh.putBucket(tokenIDParam.Uint64(), b) - return nil + return bkt, nil } func (eh *eventHandler) Finalize() (batch.KVStoreBatch, indexerCache) { @@ -296,75 +43,18 @@ func (eh *eventHandler) Finalize() (batch.KVStoreBatch, indexerCache) { return delta, dirty } -func (eh *eventHandler) putBucket(id uint64, bkt *Bucket) { +func (eh *eventHandler) PutBucket(_ address.Address, id uint64, bkt *Bucket) error { data, err := bkt.Serialize() if err != nil { - panic(errors.Wrap(err, "failed to serialize bucket")) + return errors.Wrap(err, "failed to serialize bucket") } eh.dirty.PutBucket(id, bkt) eh.delta.Put(eh.stakingBucketNS, byteutil.Uint64ToBytesBigEndian(id), data, "failed to put bucket") + return nil } -func (eh *eventHandler) delBucket(id uint64) { +func (eh *eventHandler) DeleteBucket(_ address.Address, id uint64) error { eh.dirty.DeleteBucket(id) eh.delta.Delete(eh.stakingBucketNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket") -} - -func (eh *eventHandler) handleReceipt(ctx context.Context, contractAddr string, receipt *action.Receipt) error { - if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { - return nil - } - for _, log := range receipt.Logs() { - if log.Address != contractAddr { - continue - } - if err := eh.handleEvent(ctx, log); err != nil { - return err - } - } return nil } - -func (eh *eventHandler) handleEvent(ctx context.Context, actLog *action.Log) error { - // get event abi - abiEvent, err := StakingContractABI.EventByID(common.Hash(actLog.Topics[0])) - if err != nil { - return errors.Wrapf(err, "get event abi from topic %v failed", actLog.Topics[0]) - } - - // unpack event data - event, err := abiutil.UnpackEventParam(abiEvent, actLog) - if err != nil { - return err - } - log.L().Debug("handle staking event", zap.String("event", abiEvent.Name), zap.Any("event", event)) - // handle different kinds of event - switch abiEvent.Name { - case "Staked": - return eh.HandleStakedEvent(event) - case "Locked": - return eh.HandleLockedEvent(event) - case "Unlocked": - return eh.HandleUnlockedEvent(event) - case "Unstaked": - return eh.HandleUnstakedEvent(event) - case "Merged": - return eh.HandleMergedEvent(event) - case "BucketExpanded": - return eh.HandleBucketExpandedEvent(event) - case "DelegateChanged": - return eh.HandleDelegateChangedEvent(event) - case "Withdrawal": - return eh.HandleWithdrawalEvent(event) - case "Donated": - return eh.HandleDonatedEvent(event) - case "Transfer": - return eh.HandleTransferEvent(event) - case "Approval", "ApprovalForAll", "OwnershipTransferred", "Paused", "Unpaused", "BeneficiaryChanged", - "Migrated": - // not require handling events - return nil - default: - return errors.Errorf("unknown event name %s", abiEvent.Name) - } -} diff --git a/systemcontractindex/stakingindex/eventprocessor.go b/systemcontractindex/stakingindex/eventprocessor.go new file mode 100644 index 0000000000..95c7f8a2c9 --- /dev/null +++ b/systemcontractindex/stakingindex/eventprocessor.go @@ -0,0 +1,347 @@ +package stakingindex + +import ( + "context" + _ "embed" + "math" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "go.uber.org/zap" + + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + + "github.com/iotexproject/iotex-core/v2/action" + "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking/contractstaking" + "github.com/iotexproject/iotex-core/v2/pkg/log" + "github.com/iotexproject/iotex-core/v2/pkg/util/abiutil" +) + +const ( + maxStakingNumber uint64 = math.MaxUint64 +) + +var ( + //go:embed staking_contract_abi_v3.json + stakingContractABIJSON string + // StakingContractABI is the abi of staking contract + StakingContractABI abi.ABI +) + +type ( + eventProcessor struct { + contractAddr address.Address + handler staking.EventHandler + tokenOwner map[uint64]address.Address + // context for event handler + blockCtx protocol.BlockCtx + timestamped bool + muted bool + } +) + +func init() { + var err error + StakingContractABI, err = abi.JSON(strings.NewReader(stakingContractABIJSON)) + if err != nil { + panic(err) + } +} + +func newEventProcessor(contractAddr address.Address, blkCtx protocol.BlockCtx, handler staking.EventHandler, timestamped, muted bool) *eventProcessor { + return &eventProcessor{ + contractAddr: contractAddr, + tokenOwner: make(map[uint64]address.Address), + blockCtx: blkCtx, + timestamped: timestamped, + muted: muted, + handler: handler, + } +} + +func (ep *eventProcessor) handleStakedEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + delegateParam, err := event.FieldByIDAddress(1) + if err != nil { + return err + } + amountParam, err := event.FieldByIDUint256(2) + if err != nil { + return err + } + durationParam, err := event.FieldByIDUint256(3) + if err != nil { + return err + } + owner, ok := ep.tokenOwner[tokenIDParam.Uint64()] + if !ok { + return errors.Errorf("no owner for token id %d", tokenIDParam.Uint64()) + } + createdAt := ep.blockCtx.BlockHeight + if ep.timestamped { + createdAt = uint64(ep.blockCtx.BlockTimeStamp.Unix()) + } + bucket := &Bucket{ + Candidate: delegateParam, + Owner: owner, + StakedAmount: amountParam, + StakedDuration: durationParam.Uint64(), + CreatedAt: createdAt, + UnlockedAt: maxStakingNumber, + UnstakedAt: maxStakingNumber, + IsTimestampBased: ep.timestamped, + Muted: ep.muted, + } + return ep.handler.PutBucket(ep.contractAddr, tokenIDParam.Uint64(), bucket) +} + +func (ep *eventProcessor) handleLockedEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + durationParam, err := event.FieldByIDUint256(1) + if err != nil { + return err + } + + bkt, err := ep.handler.DeductBucket(ep.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err + } + bkt.StakedDuration = durationParam.Uint64() + bkt.UnlockedAt = maxStakingNumber + bkt.Muted = ep.muted + return ep.handler.PutBucket(ep.contractAddr, tokenIDParam.Uint64(), bkt) +} + +func (ep *eventProcessor) handleUnlockedEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + + bkt, err := ep.handler.DeductBucket(ep.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err + } + bkt.UnlockedAt = ep.blockCtx.BlockHeight + if ep.timestamped { + bkt.UnlockedAt = uint64(ep.blockCtx.BlockTimeStamp.Unix()) + } + return ep.handler.PutBucket(ep.contractAddr, tokenIDParam.Uint64(), bkt) +} + +func (ep *eventProcessor) handleUnstakedEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + + bkt, err := ep.handler.DeductBucket(ep.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err + } + bkt.UnstakedAt = ep.blockCtx.BlockHeight + if ep.timestamped { + bkt.UnstakedAt = uint64(ep.blockCtx.BlockTimeStamp.Unix()) + } + return ep.handler.PutBucket(ep.contractAddr, tokenIDParam.Uint64(), bkt) +} + +func (ep *eventProcessor) handleDelegateChangedEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + delegateParam, err := event.FieldByIDAddress(1) + if err != nil { + return err + } + + bkt, err := ep.handler.DeductBucket(ep.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err + } + bkt.Candidate = delegateParam + return ep.handler.PutBucket(ep.contractAddr, tokenIDParam.Uint64(), bkt) +} + +func (ep *eventProcessor) handleWithdrawalEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + + return ep.handler.DeleteBucket(ep.contractAddr, tokenIDParam.Uint64()) +} + +func (ep *eventProcessor) handleTransferEvent(event *abiutil.EventParam) error { + to, err := event.FieldByIDAddress(1) + if err != nil { + return err + } + tokenIDParam, err := event.FieldByIDUint256(2) + if err != nil { + return err + } + + tokenID := tokenIDParam.Uint64() + // cache token owner for stake event + ep.tokenOwner[tokenID] = to + // update bucket owner if token exists + bkt, err := ep.handler.DeductBucket(ep.contractAddr, tokenID) + switch errors.Cause(err) { + case nil: + bkt.Owner = to + return ep.handler.PutBucket(ep.contractAddr, tokenID, bkt) + case contractstaking.ErrBucketNotExist: + return nil + default: + return err + } +} + +func (ep *eventProcessor) handleMergedEvent(event *abiutil.EventParam) error { + tokenIDsParam, err := event.FieldByIDUint256Slice(0) + if err != nil { + return err + } + amountParam, err := event.FieldByIDUint256(1) + if err != nil { + return err + } + durationParam, err := event.FieldByIDUint256(2) + if err != nil { + return err + } + + // merge to the first bucket + b, err := ep.handler.DeductBucket(ep.contractAddr, tokenIDsParam[0].Uint64()) + if err != nil { + return err + } + b.StakedAmount = amountParam + b.StakedDuration = durationParam.Uint64() + b.UnlockedAt = maxStakingNumber + b.Muted = ep.muted + for i := 1; i < len(tokenIDsParam); i++ { + if err := ep.handler.DeleteBucket(ep.contractAddr, tokenIDsParam[i].Uint64()); err != nil { + return err + } + } + return ep.handler.PutBucket(ep.contractAddr, tokenIDsParam[0].Uint64(), b) +} + +func (ep *eventProcessor) handleBucketExpandedEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + amountParam, err := event.FieldByIDUint256(1) + if err != nil { + return err + } + durationParam, err := event.FieldByIDUint256(2) + if err != nil { + return err + } + + b, err := ep.handler.DeductBucket(ep.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err + } + b.StakedAmount = amountParam + b.StakedDuration = durationParam.Uint64() + b.Muted = ep.muted + return ep.handler.PutBucket(ep.contractAddr, tokenIDParam.Uint64(), b) +} + +func (ep *eventProcessor) handleDonatedEvent(event *abiutil.EventParam) error { + tokenIDParam, err := event.FieldByIDUint256(0) + if err != nil { + return err + } + amountParam, err := event.FieldByIDUint256(2) + if err != nil { + return err + } + + b, err := ep.handler.DeductBucket(ep.contractAddr, tokenIDParam.Uint64()) + if err != nil { + return err + } + b.StakedAmount.Sub(b.StakedAmount, amountParam) + b.Muted = ep.muted + return ep.handler.PutBucket(ep.contractAddr, tokenIDParam.Uint64(), b) +} + +func (ep *eventProcessor) ProcessReceipts(ctx context.Context, receipts ...*action.Receipt) error { + expectedContractAddr := ep.contractAddr.String() + for _, receipt := range receipts { + if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { + continue + } + for _, log := range receipt.Logs() { + if log.Address != expectedContractAddr { + continue + } + if err := ep.processEvent(ctx, log); err != nil { + return errors.Wrapf(err, "handle %d log in receipt %x failed", log.Index, receipt.ActionHash) + } + } + } + return nil +} + +func (ep *eventProcessor) processEvent(ctx context.Context, actLog *action.Log) error { + // get event abi + abiEvent, err := StakingContractABI.EventByID(common.Hash(actLog.Topics[0])) + if err != nil { + return errors.Wrapf(err, "get event abi from topic %v failed", actLog.Topics[0]) + } + + // unpack event data + event, err := abiutil.UnpackEventParam(abiEvent, actLog) + if err != nil { + return err + } + log.L().Debug("handle staking event", zap.String("event", abiEvent.Name), zap.Any("event", event)) + // handle different kinds of event + switch abiEvent.Name { + case "Staked": + return ep.handleStakedEvent(event) + case "Locked": + return ep.handleLockedEvent(event) + case "Unlocked": + return ep.handleUnlockedEvent(event) + case "Unstaked": + return ep.handleUnstakedEvent(event) + case "Merged": + return ep.handleMergedEvent(event) + case "BucketExpanded": + return ep.handleBucketExpandedEvent(event) + case "DelegateChanged": + return ep.handleDelegateChangedEvent(event) + case "Withdrawal": + return ep.handleWithdrawalEvent(event) + case "Donated": + return ep.handleDonatedEvent(event) + case "Transfer": + return ep.handleTransferEvent(event) + case "Approval", "ApprovalForAll", "OwnershipTransferred", "Paused", "Unpaused", "BeneficiaryChanged", + "Migrated": + // not require handling events + return nil + default: + return errors.Errorf("unknown event name %s", abiEvent.Name) + } +} diff --git a/systemcontractindex/stakingindex/index.go b/systemcontractindex/stakingindex/index.go index 00327cebc0..74041f01ef 100644 --- a/systemcontractindex/stakingindex/index.go +++ b/systemcontractindex/stakingindex/index.go @@ -14,10 +14,8 @@ import ( "github.com/iotexproject/iotex-core/v2/action/protocol/staking/contractstaking" "github.com/iotexproject/iotex-core/v2/blockchain/block" "github.com/iotexproject/iotex-core/v2/db" - "github.com/iotexproject/iotex-core/v2/db/batch" "github.com/iotexproject/iotex-core/v2/pkg/lifecycle" "github.com/iotexproject/iotex-core/v2/pkg/log" - "github.com/iotexproject/iotex-core/v2/pkg/util/abiutil" "github.com/iotexproject/iotex-core/v2/systemcontractindex" ) @@ -45,19 +43,7 @@ type ( TotalBucketCount(height uint64) (uint64, error) PutBlock(ctx context.Context, blk *block.Block) error LoadStakeView(context.Context, protocol.StateReader) (staking.ContractStakeView, error) - } - stakingEventHandler interface { - HandleStakedEvent(event *abiutil.EventParam) error - HandleLockedEvent(event *abiutil.EventParam) error - HandleUnlockedEvent(event *abiutil.EventParam) error - HandleUnstakedEvent(event *abiutil.EventParam) error - HandleDelegateChangedEvent(event *abiutil.EventParam) error - HandleWithdrawalEvent(event *abiutil.EventParam) error - HandleTransferEvent(event *abiutil.EventParam) error - HandleMergedEvent(event *abiutil.EventParam) error - HandleBucketExpandedEvent(event *abiutil.EventParam) error - HandleDonatedEvent(event *abiutil.EventParam) error - Finalize() (batch.KVStoreBatch, indexerCache) + CreateEventProcessor(context.Context, staking.EventHandler) staking.EventProcessor } // Indexer is the staking indexer Indexer struct { @@ -132,6 +118,18 @@ func (s *Indexer) Stop(ctx context.Context) error { return s.common.Stop(ctx) } +// CreateEventProcessor creates a new event processor +func (s *Indexer) CreateEventProcessor(ctx context.Context, handler staking.EventHandler) staking.EventProcessor { + blkCtx := protocol.MustGetBlockCtx(ctx) + return newEventProcessor( + s.common.ContractAddress(), + blkCtx, + handler, + s.timestamped, + s.muteHeight > 0 && blkCtx.BlockHeight >= s.muteHeight, + ) +} + // LoadStakeView loads the contract stake view from state reader func (s *Indexer) LoadStakeView(ctx context.Context, sr protocol.StateReader) (staking.ContractStakeView, error) { s.mutex.RLock() @@ -303,17 +301,22 @@ func (s *Indexer) PutBlock(ctx context.Context, blk *block.Block) error { } // handle events of block muted := s.muteHeight > 0 && blk.Height() >= s.muteHeight - handler := newEventHandler(s.bucketNS, newWrappedCache(s.cache), protocol.MustGetBlockCtx(ctx), s.timestamped, muted) - for _, receipt := range blk.Receipts { - if err := handler.handleReceipt(ctx, s.common.ContractAddress().String(), receipt); err != nil { - return errors.Wrapf(err, "handle receipt %x failed", receipt.ActionHash) - } + handler := newEventHandler(s.bucketNS, newWrappedCache(s.cache)) + processor := newEventProcessor( + s.common.ContractAddress(), + protocol.MustGetBlockCtx(ctx), + handler, + s.timestamped, + muted, + ) + if err := processor.ProcessReceipts(ctx, blk.Receipts...); err != nil { + return err } // commit return s.commit(ctx, handler, blk.Height()) } -func (s *Indexer) commit(ctx context.Context, handler stakingEventHandler, height uint64) error { +func (s *Indexer) commit(ctx context.Context, handler *eventHandler, height uint64) error { delta, dirty := handler.Finalize() // update db if err := s.common.Commit(height, delta); err != nil { diff --git a/systemcontractindex/stakingindex/stakeview.go b/systemcontractindex/stakingindex/stakeview.go index dd49e80278..5b18dd65fc 100644 --- a/systemcontractindex/stakingindex/stakeview.go +++ b/systemcontractindex/stakingindex/stakeview.go @@ -54,7 +54,7 @@ func (s *stakeView) IsDirty() bool { return s.cache.IsDirty() } -func (s *stakeView) WriteBuckets(sm protocol.StateManager) error { +func (s *stakeView) Migrate(sm protocol.StateManager) error { ids := s.cache.BucketIdxs() slices.Sort(ids) buckets := s.cache.Buckets(ids) @@ -92,8 +92,9 @@ func (s *stakeView) CreatePreStates(ctx context.Context) error { func (s *stakeView) Handle(ctx context.Context, receipt *action.Receipt) error { blkCtx := protocol.MustGetBlockCtx(ctx) muted := s.muteHeight > 0 && blkCtx.BlockHeight >= s.muteHeight - handler := newEventHandler(s.bucketNS, s.cache, blkCtx, s.timestamped, muted) - return handler.handleReceipt(ctx, s.contractAddr.String(), receipt) + return newEventProcessor( + s.contractAddr, blkCtx, newEventHandler(s.bucketNS, s.cache), s.timestamped, muted, + ).ProcessReceipts(ctx, receipt) } func (s *stakeView) AddBlockReceipts(ctx context.Context, receipts []*action.Receipt) error { @@ -107,11 +108,10 @@ func (s *stakeView) AddBlockReceipts(ctx context.Context, receipts []*action.Rec } ctx = protocol.WithBlockCtx(ctx, blkCtx) muted := s.muteHeight > 0 && height >= s.muteHeight - handler := newEventHandler(s.bucketNS, s.cache, blkCtx, s.timestamped, muted) - for _, receipt := range receipts { - if err := handler.handleReceipt(ctx, s.contractAddr.String(), receipt); err != nil { - return errors.Wrapf(err, "failed to handle receipt at height %d", height) - } + if err := newEventProcessor( + s.contractAddr, blkCtx, newEventHandler(s.bucketNS, s.cache), s.timestamped, muted, + ).ProcessReceipts(ctx, receipts...); err != nil { + return errors.Wrapf(err, "failed to handle receipts at height %d", height) } s.height = height return nil diff --git a/test/mock/mock_chainmanager/mock_chainmanager.go b/test/mock/mock_chainmanager/mock_chainmanager.go index 89815724ac..acf4d711d4 100644 --- a/test/mock/mock_chainmanager/mock_chainmanager.go +++ b/test/mock/mock_chainmanager/mock_chainmanager.go @@ -285,3 +285,190 @@ func (mr *MockStateManagerMockRecorder) WriteView(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteView", reflect.TypeOf((*MockStateManager)(nil).WriteView), arg0, arg1) } + +// MockStateManagerWithCloser is a mock of StateManagerWithCloser interface. +type MockStateManagerWithCloser struct { + ctrl *gomock.Controller + recorder *MockStateManagerWithCloserMockRecorder + isgomock struct{} +} + +// MockStateManagerWithCloserMockRecorder is the mock recorder for MockStateManagerWithCloser. +type MockStateManagerWithCloserMockRecorder struct { + mock *MockStateManagerWithCloser +} + +// NewMockStateManagerWithCloser creates a new mock instance. +func NewMockStateManagerWithCloser(ctrl *gomock.Controller) *MockStateManagerWithCloser { + mock := &MockStateManagerWithCloser{ctrl: ctrl} + mock.recorder = &MockStateManagerWithCloserMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStateManagerWithCloser) EXPECT() *MockStateManagerWithCloserMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockStateManagerWithCloser) Close() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Close") +} + +// Close indicates an expected call of Close. +func (mr *MockStateManagerWithCloserMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockStateManagerWithCloser)(nil).Close)) +} + +// DelState mocks base method. +func (m *MockStateManagerWithCloser) DelState(arg0 ...protocol.StateOption) (uint64, error) { + m.ctrl.T.Helper() + varargs := []any{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DelState", varargs...) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DelState indicates an expected call of DelState. +func (mr *MockStateManagerWithCloserMockRecorder) DelState(arg0 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DelState", reflect.TypeOf((*MockStateManagerWithCloser)(nil).DelState), arg0...) +} + +// Height mocks base method. +func (m *MockStateManagerWithCloser) Height() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Height") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Height indicates an expected call of Height. +func (mr *MockStateManagerWithCloserMockRecorder) Height() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockStateManagerWithCloser)(nil).Height)) +} + +// PutState mocks base method. +func (m *MockStateManagerWithCloser) PutState(arg0 any, arg1 ...protocol.StateOption) (uint64, error) { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PutState", varargs...) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PutState indicates an expected call of PutState. +func (mr *MockStateManagerWithCloserMockRecorder) PutState(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutState", reflect.TypeOf((*MockStateManagerWithCloser)(nil).PutState), varargs...) +} + +// ReadView mocks base method. +func (m *MockStateManagerWithCloser) ReadView(arg0 string) (protocol.View, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadView", arg0) + ret0, _ := ret[0].(protocol.View) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadView indicates an expected call of ReadView. +func (mr *MockStateManagerWithCloserMockRecorder) ReadView(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadView", reflect.TypeOf((*MockStateManagerWithCloser)(nil).ReadView), arg0) +} + +// Revert mocks base method. +func (m *MockStateManagerWithCloser) Revert(arg0 int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Revert", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Revert indicates an expected call of Revert. +func (mr *MockStateManagerWithCloserMockRecorder) Revert(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Revert", reflect.TypeOf((*MockStateManagerWithCloser)(nil).Revert), arg0) +} + +// Snapshot mocks base method. +func (m *MockStateManagerWithCloser) Snapshot() int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Snapshot") + ret0, _ := ret[0].(int) + return ret0 +} + +// Snapshot indicates an expected call of Snapshot. +func (mr *MockStateManagerWithCloserMockRecorder) Snapshot() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Snapshot", reflect.TypeOf((*MockStateManagerWithCloser)(nil).Snapshot)) +} + +// State mocks base method. +func (m *MockStateManagerWithCloser) State(arg0 any, arg1 ...protocol.StateOption) (uint64, error) { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "State", varargs...) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// State indicates an expected call of State. +func (mr *MockStateManagerWithCloserMockRecorder) State(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "State", reflect.TypeOf((*MockStateManagerWithCloser)(nil).State), varargs...) +} + +// States mocks base method. +func (m *MockStateManagerWithCloser) States(arg0 ...protocol.StateOption) (uint64, state.Iterator, error) { + m.ctrl.T.Helper() + varargs := []any{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "States", varargs...) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(state.Iterator) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// States indicates an expected call of States. +func (mr *MockStateManagerWithCloserMockRecorder) States(arg0 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "States", reflect.TypeOf((*MockStateManagerWithCloser)(nil).States), arg0...) +} + +// WriteView mocks base method. +func (m *MockStateManagerWithCloser) WriteView(arg0 string, arg1 protocol.View) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteView", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// WriteView indicates an expected call of WriteView. +func (mr *MockStateManagerWithCloserMockRecorder) WriteView(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteView", reflect.TypeOf((*MockStateManagerWithCloser)(nil).WriteView), arg0, arg1) +}