diff --git a/action/protocol/poll/blockmeta.go b/action/protocol/poll/blockmeta.go index 13ae8fd2e4..b32e90eb6d 100644 --- a/action/protocol/poll/blockmeta.go +++ b/action/protocol/poll/blockmeta.go @@ -12,10 +12,7 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" - "github.com/iotexproject/iotex-core/v2/action/protocol" "github.com/iotexproject/iotex-core/v2/action/protocol/poll/blockmetapb" - "github.com/iotexproject/iotex-core/v2/pkg/util/assertions" - "github.com/iotexproject/iotex-core/v2/state/factory/erigonstore" "github.com/iotexproject/iotex-core/v2/systemcontracts" ) @@ -26,10 +23,6 @@ type BlockMeta struct { MintTime time.Time } -func init() { - assertions.MustNoError(erigonstore.GetObjectStorageRegistry().RegisterPollBlockMeta(protocol.SystemNamespace, &BlockMeta{})) -} - // NewBlockMeta constructs new blockmeta struct with given fieldss func NewBlockMeta(height uint64, producer string, mintTime time.Time) *BlockMeta { return &BlockMeta{ diff --git a/action/protocol/rewarding/admin.go b/action/protocol/rewarding/admin.go index f388f6c9ee..1d67abb3ad 100644 --- a/action/protocol/rewarding/admin.go +++ b/action/protocol/rewarding/admin.go @@ -17,9 +17,6 @@ import ( "github.com/iotexproject/iotex-core/v2/action/protocol" "github.com/iotexproject/iotex-core/v2/action/protocol/rewarding/rewardingpb" "github.com/iotexproject/iotex-core/v2/blockchain/genesis" - "github.com/iotexproject/iotex-core/v2/pkg/util/assertions" - "github.com/iotexproject/iotex-core/v2/state" - "github.com/iotexproject/iotex-core/v2/state/factory/erigonstore" "github.com/iotexproject/iotex-core/v2/systemcontracts" ) @@ -34,14 +31,6 @@ type admin struct { productivityThreshold uint64 } -func init() { - registry := erigonstore.GetObjectStorageRegistry() - assertions.MustNoError(registry.RegisterRewardingV1(state.AccountKVNamespace, &admin{})) - assertions.MustNoError(registry.RegisterRewardingV1(state.AccountKVNamespace, &exempt{})) - assertions.MustNoError(registry.RegisterRewardingV2(_v2RewardingNamespace, &admin{})) - assertions.MustNoError(registry.RegisterRewardingV2(_v2RewardingNamespace, &exempt{})) -} - // Serialize serializes admin state into bytes func (a admin) Serialize() ([]byte, error) { gen := rewardingpb.Admin{ diff --git a/action/protocol/rewarding/fund.go b/action/protocol/rewarding/fund.go index 95bbc49d0f..2131d447fe 100644 --- a/action/protocol/rewarding/fund.go +++ b/action/protocol/rewarding/fund.go @@ -19,9 +19,7 @@ import ( "github.com/iotexproject/iotex-core/v2/action/protocol" accountutil "github.com/iotexproject/iotex-core/v2/action/protocol/account/util" "github.com/iotexproject/iotex-core/v2/action/protocol/rewarding/rewardingpb" - "github.com/iotexproject/iotex-core/v2/pkg/util/assertions" "github.com/iotexproject/iotex-core/v2/state" - "github.com/iotexproject/iotex-core/v2/state/factory/erigonstore" "github.com/iotexproject/iotex-core/v2/systemcontracts" ) @@ -32,12 +30,6 @@ type fund struct { unclaimedBalance *big.Int } -func init() { - registry := erigonstore.GetObjectStorageRegistry() - assertions.MustNoError(registry.RegisterRewardingV1(state.AccountKVNamespace, &fund{})) - assertions.MustNoError(registry.RegisterRewardingV2(_v2RewardingNamespace, &fund{})) -} - // Serialize serializes fund state into bytes func (f fund) Serialize() ([]byte, error) { gen := rewardingpb.Fund{ diff --git a/action/protocol/rewarding/reward.go b/action/protocol/rewarding/reward.go index 76346217b3..98ee8414ff 100644 --- a/action/protocol/rewarding/reward.go +++ b/action/protocol/rewarding/reward.go @@ -25,23 +25,13 @@ import ( "github.com/iotexproject/iotex-core/v2/action/protocol/staking" "github.com/iotexproject/iotex-core/v2/pkg/enc" "github.com/iotexproject/iotex-core/v2/pkg/log" - "github.com/iotexproject/iotex-core/v2/pkg/util/assertions" "github.com/iotexproject/iotex-core/v2/state" - "github.com/iotexproject/iotex-core/v2/state/factory/erigonstore" "github.com/iotexproject/iotex-core/v2/systemcontracts" ) // rewardHistory is the dummy struct to record a reward. Only key matters. type rewardHistory struct{} -func init() { - registry := erigonstore.GetObjectStorageRegistry() - assertions.MustNoError(registry.RegisterRewardingV1(state.AccountKVNamespace, &rewardHistory{})) - assertions.MustNoError(registry.RegisterRewardingV1(state.AccountKVNamespace, &rewardAccount{})) - assertions.MustNoError(registry.RegisterRewardingV2(_v2RewardingNamespace, &rewardHistory{})) - assertions.MustNoError(registry.RegisterRewardingV2(_v2RewardingNamespace, &rewardAccount{})) -} - // Serialize serializes reward history state into bytes func (b rewardHistory) Serialize() ([]byte, error) { gen := rewardingpb.RewardHistory{} diff --git a/action/protocol/staking/bucket_index.go b/action/protocol/staking/bucket_index.go index 698abd6e9e..4de0f37629 100644 --- a/action/protocol/staking/bucket_index.go +++ b/action/protocol/staking/bucket_index.go @@ -12,6 +12,7 @@ import ( "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb" + "github.com/iotexproject/iotex-core/v2/systemcontracts" ) type ( @@ -51,6 +52,20 @@ func (bis *BucketIndices) Serialize() ([]byte, error) { return proto.Marshal(bis.Proto()) } +// Encode encodes bucket indices into generic value +func (bis *BucketIndices) Encode() (systemcontracts.GenericValue, error) { + data, err := bis.Serialize() + if err != nil { + return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize bucket indices") + } + return systemcontracts.GenericValue{PrimaryData: data}, nil +} + +// Decode decodes bucket indices from generic value +func (bis *BucketIndices) Decode(gv systemcontracts.GenericValue) error { + return bis.Deserialize(gv.PrimaryData) +} + func (bis *BucketIndices) addBucketIndex(index uint64) { *bis = append(*bis, index) } diff --git a/action/protocol/staking/bucket_pool.go b/action/protocol/staking/bucket_pool.go index c5d998edcb..7616c0456d 100644 --- a/action/protocol/staking/bucket_pool.go +++ b/action/protocol/staking/bucket_pool.go @@ -9,11 +9,13 @@ import ( "math/big" "github.com/iotexproject/go-pkgs/hash" + "github.com/pkg/errors" "google.golang.org/protobuf/proto" "github.com/iotexproject/iotex-core/v2/action/protocol" "github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb" "github.com/iotexproject/iotex-core/v2/state" + "github.com/iotexproject/iotex-core/v2/systemcontracts" ) // const @@ -91,6 +93,20 @@ func (t *totalAmount) SubBalance(amount *big.Int) error { return nil } +// Encode encodes total amount into generic value +func (t *totalAmount) Encode() (systemcontracts.GenericValue, error) { + data, err := t.Serialize() + if err != nil { + return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize total amount") + } + return systemcontracts.GenericValue{PrimaryData: data}, nil +} + +// Decode decodes total amount from generic value +func (t *totalAmount) Decode(gv systemcontracts.GenericValue) error { + return t.Deserialize(gv.PrimaryData) +} + // IsDirty returns true if the bucket pool is dirty func (bp *BucketPool) IsDirty() bool { return bp.dirty diff --git a/action/protocol/staking/candidate.go b/action/protocol/staking/candidate.go index 413821e49c..450ae2e83c 100644 --- a/action/protocol/staking/candidate.go +++ b/action/protocol/staking/candidate.go @@ -18,6 +18,7 @@ import ( "github.com/iotexproject/iotex-core/v2/action" "github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb" "github.com/iotexproject/iotex-core/v2/state" + "github.com/iotexproject/iotex-core/v2/systemcontracts" ) type ( @@ -194,6 +195,50 @@ func (d *Candidate) GetIdentifier() address.Address { return d.Identifier } +// Encode encodes candidate into generic value +func (d *Candidate) Encode() (systemcontracts.GenericValue, error) { + var ( + primaryData []byte + secondaryData []byte + err error + value systemcontracts.GenericValue + ) + if d.Votes.Sign() > 0 { + secondaryData, err = proto.Marshal(&stakingpb.Candidate{Votes: d.Votes.String()}) + if err != nil { + return value, errors.Wrap(err, "failed to marshal candidate votes") + } + } + clone := d.Clone() + clone.Votes = big.NewInt(0) + primaryData, err = clone.Serialize() + if err != nil { + return value, errors.Wrap(err, "failed to serialize candidate") + } + value.PrimaryData = primaryData + value.SecondaryData = secondaryData + return value, nil +} + +// Decode decodes candidate from generic value +func (d *Candidate) Decode(gv systemcontracts.GenericValue) error { + if err := d.Deserialize(gv.PrimaryData); err != nil { + return errors.Wrap(err, "failed to deserialize candidate") + } + if len(gv.SecondaryData) > 0 { + votes := &stakingpb.Candidate{} + if err := proto.Unmarshal(gv.SecondaryData, votes); err != nil { + return errors.Wrap(err, "failed to unmarshal candidate votes") + } + vote, ok := new(big.Int).SetString(votes.Votes, 10) + if !ok { + return errors.Wrapf(action.ErrInvalidAmount, "failed to parse candidate votes: %s", votes.Votes) + } + d.Votes = vote + } + return nil +} + func (d *Candidate) toProto() (*stakingpb.Candidate, error) { if d.Owner == nil || d.Operator == nil || d.Reward == nil || len(d.Name) == 0 || d.Votes == nil || d.SelfStake == nil { @@ -360,6 +405,20 @@ func (l *CandidateList) Deserialize(buf []byte) error { return nil } +// Encode encodes candidate list into generic value +func (l *CandidateList) Encode() (systemcontracts.GenericValue, error) { + data, err := l.Serialize() + if err != nil { + return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize candidate list") + } + return systemcontracts.GenericValue{PrimaryData: data}, nil +} + +// Decode decodes candidate list from generic value +func (l *CandidateList) Decode(gv systemcontracts.GenericValue) error { + return l.Deserialize(gv.PrimaryData) +} + func (l CandidateList) toStateCandidateList() (state.CandidateList, error) { list := make(state.CandidateList, 0, len(l)) for _, c := range l { diff --git a/action/protocol/staking/candidate_statemanager.go b/action/protocol/staking/candidate_statemanager.go index 580bc833e0..25fc43c58f 100644 --- a/action/protocol/staking/candidate_statemanager.go +++ b/action/protocol/staking/candidate_statemanager.go @@ -220,7 +220,9 @@ func (csm *candSM) putBucket(bucket *VoteBucket) (uint64, error) { func (csm *candSM) delBucket(index uint64) error { _, err := csm.DelState( protocol.NamespaceOption(_stakingNameSpace), - protocol.KeyOption(bucketKey(index))) + protocol.KeyOption(bucketKey(index)), + protocol.ObjectOption(&VoteBucket{}), + ) return err } @@ -295,7 +297,9 @@ func (csm *candSM) delBucketIndex(addr address.Address, prefix byte, index uint6 if len(bis) == 0 { _, err = csm.DelState( protocol.NamespaceOption(_stakingNameSpace), - protocol.KeyOption(key)) + protocol.KeyOption(key), + protocol.ObjectOption(&BucketIndices{}), + ) } else { _, err = csm.PutState( &bis, @@ -319,7 +323,7 @@ func (csm *candSM) putCandBucketIndex(addr address.Address, index uint64) error } func (csm *candSM) delCandidate(name address.Address) error { - _, err := csm.DelState(protocol.NamespaceOption(_candidateNameSpace), protocol.KeyOption(name.Bytes())) + _, err := csm.DelState(protocol.NamespaceOption(_candidateNameSpace), protocol.KeyOption(name.Bytes()), protocol.ObjectOption(&Candidate{})) return err } diff --git a/action/protocol/staking/candidate_statereader.go b/action/protocol/staking/candidate_statereader.go index 402e00c06d..8d0ad5f6b8 100644 --- a/action/protocol/staking/candidate_statereader.go +++ b/action/protocol/staking/candidate_statereader.go @@ -216,6 +216,7 @@ func (c *candSR) NativeBuckets() ([]*VoteBucket, uint64, error) { } return keys, nil }), + protocol.ObjectOption(&VoteBucket{}), ) if err != nil { return nil, height, err @@ -297,7 +298,7 @@ func (c *candSR) CandidateByAddress(name address.Address) (*Candidate, uint64, e } func (c *candSR) CreateCandidateCenter() (*CandidateCenter, uint64, error) { - height, iter, err := c.States(protocol.NamespaceOption(_candidateNameSpace)) + height, iter, err := c.States(protocol.NamespaceOption(_candidateNameSpace), protocol.ObjectOption(&Candidate{})) var cands CandidateList switch errors.Cause(err) { case nil: diff --git a/action/protocol/staking/endorsement.go b/action/protocol/staking/endorsement.go index 9ce2ba2a80..1b335a8088 100644 --- a/action/protocol/staking/endorsement.go +++ b/action/protocol/staking/endorsement.go @@ -7,6 +7,7 @@ import ( "google.golang.org/protobuf/proto" "github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb" + "github.com/iotexproject/iotex-core/v2/systemcontracts" ) // EndorsementStatus @@ -84,6 +85,20 @@ func (e *Endorsement) Deserialize(buf []byte) error { return e.fromProto(pb) } +// Encode encodes endorsement into generic value +func (e *Endorsement) Encode() (systemcontracts.GenericValue, error) { + data, err := e.Serialize() + if err != nil { + return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize endorsement") + } + return systemcontracts.GenericValue{PrimaryData: data}, nil +} + +// Decode decodes endorsement from generic value +func (e *Endorsement) Decode(gv systemcontracts.GenericValue) error { + return e.Deserialize(gv.PrimaryData) +} + func (e *Endorsement) toProto() (*stakingpb.Endorsement, error) { return &stakingpb.Endorsement{ ExpireHeight: e.ExpireHeight, diff --git a/action/protocol/staking/endorsement_statemanager.go b/action/protocol/staking/endorsement_statemanager.go index b002512c8a..c273f8d3c1 100644 --- a/action/protocol/staking/endorsement_statemanager.go +++ b/action/protocol/staking/endorsement_statemanager.go @@ -36,7 +36,7 @@ func (esm *EndorsementStateManager) Put(bucketIndex uint64, endorse *Endorsement // Delete deletes the endorsement of a bucket func (esm *EndorsementStateManager) Delete(bucketIndex uint64) error { - _, err := esm.DelState(protocol.NamespaceOption(_stakingNameSpace), protocol.KeyOption(endorsementKey(bucketIndex))) + _, err := esm.DelState(protocol.NamespaceOption(_stakingNameSpace), protocol.KeyOption(endorsementKey(bucketIndex)), protocol.ObjectOption(&Endorsement{})) return err } diff --git a/action/protocol/staking/staking_statereader_test.go b/action/protocol/staking/staking_statereader_test.go index e65654a904..162ec27605 100644 --- a/action/protocol/staking/staking_statereader_test.go +++ b/action/protocol/staking/staking_statereader_test.go @@ -165,7 +165,7 @@ func TestStakingStateReader(t *testing.T) { } t.Run("readStateBuckets", func(t *testing.T) { sf, _, stakeSR, ctx, r := prepare(t) - sf.EXPECT().States(gomock.Any(), gomock.Any()).DoAndReturn(func(arg0 ...protocol.StateOption) (uint64, state.Iterator, error) { + sf.EXPECT().States(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(arg0 ...protocol.StateOption) (uint64, state.Iterator, error) { iter, err := state.NewIterator(keys, states) r.NoError(err) return uint64(1), iter, nil @@ -195,7 +195,7 @@ func TestStakingStateReader(t *testing.T) { }) t.Run("readStateBucketsWithEndorsement", func(t *testing.T) { sf, _, stakeSR, ctx, r := prepare(t) - sf.EXPECT().States(gomock.Any(), gomock.Any()).DoAndReturn(func(arg0 ...protocol.StateOption) (uint64, state.Iterator, error) { + sf.EXPECT().States(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(arg0 ...protocol.StateOption) (uint64, state.Iterator, error) { iter, err := state.NewIterator(keys, states) r.NoError(err) return uint64(1), iter, nil diff --git a/action/protocol/staking/vote_bucket.go b/action/protocol/staking/vote_bucket.go index 890b21cf6b..c425146d1c 100644 --- a/action/protocol/staking/vote_bucket.go +++ b/action/protocol/staking/vote_bucket.go @@ -20,6 +20,7 @@ import ( "github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb" "github.com/iotexproject/iotex-core/v2/blockchain/genesis" "github.com/iotexproject/iotex-core/v2/pkg/util/byteutil" + "github.com/iotexproject/iotex-core/v2/systemcontracts" ) type ( @@ -73,6 +74,20 @@ func (vb *VoteBucket) Deserialize(buf []byte) error { return vb.fromProto(pb) } +// Encode encodes VoteBucket into generic value +func (vb *VoteBucket) Encode() (systemcontracts.GenericValue, error) { + data, err := vb.Serialize() + if err != nil { + return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize bucket") + } + return systemcontracts.GenericValue{PrimaryData: data}, nil +} + +// Decode decodes VoteBucket from generic value +func (vb *VoteBucket) Decode(gv systemcontracts.GenericValue) error { + return vb.Deserialize(gv.PrimaryData) +} + func (vb *VoteBucket) fromProto(pb *stakingpb.Bucket) error { vote, ok := new(big.Int).SetString(pb.GetStakedAmount(), 10) if !ok { @@ -209,6 +224,20 @@ func (tc *totalBucketCount) Count() uint64 { return tc.count } +// Encode encodes totalBucketCount into generic value +func (tc *totalBucketCount) Encode() (systemcontracts.GenericValue, error) { + data, err := tc.Serialize() + if err != nil { + return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize total bucket count") + } + return systemcontracts.GenericValue{PrimaryData: data}, nil +} + +// Decode decodes totalBucketCount from generic value +func (tc *totalBucketCount) Decode(gv systemcontracts.GenericValue) error { + return tc.Deserialize(gv.PrimaryData) +} + func bucketKey(index uint64) []byte { key := []byte{_bucket} return append(key, byteutil.Uint64ToBytesBigEndian(index)...) diff --git a/action/protocol/vote/probationlist.go b/action/protocol/vote/probationlist.go index 8cd8029e0e..8d931e9c54 100644 --- a/action/protocol/vote/probationlist.go +++ b/action/protocol/vote/probationlist.go @@ -13,9 +13,6 @@ import ( "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/iotexproject/iotex-core/v2/action/protocol" - "github.com/iotexproject/iotex-core/v2/pkg/util/assertions" - "github.com/iotexproject/iotex-core/v2/state/factory/erigonstore" "github.com/iotexproject/iotex-core/v2/systemcontracts" ) @@ -25,10 +22,6 @@ type ProbationList struct { IntensityRate uint32 } -func init() { - assertions.MustNoError(erigonstore.GetObjectStorageRegistry().RegisterPollProbationList(protocol.SystemNamespace, &ProbationList{})) -} - // NewProbationList returns a new probation list func NewProbationList(intensity uint32) *ProbationList { return &ProbationList{ diff --git a/action/protocol/vote/unproductivedelegate.go b/action/protocol/vote/unproductivedelegate.go index 7822b690b4..afe05612a0 100644 --- a/action/protocol/vote/unproductivedelegate.go +++ b/action/protocol/vote/unproductivedelegate.go @@ -11,10 +11,7 @@ import ( "github.com/pkg/errors" "google.golang.org/protobuf/proto" - "github.com/iotexproject/iotex-core/v2/action/protocol" updpb "github.com/iotexproject/iotex-core/v2/action/protocol/vote/unproductivedelegatepb" - "github.com/iotexproject/iotex-core/v2/pkg/util/assertions" - "github.com/iotexproject/iotex-core/v2/state/factory/erigonstore" "github.com/iotexproject/iotex-core/v2/systemcontracts" ) @@ -25,10 +22,6 @@ type UnproductiveDelegate struct { cacheSize uint64 } -func init() { - assertions.MustNoError(erigonstore.GetObjectStorageRegistry().RegisterPollUnproductiveDelegate(protocol.SystemNamespace, &UnproductiveDelegate{})) -} - // NewUnproductiveDelegate creates new UnproductiveDelegate with probationperiod and cacheSize func NewUnproductiveDelegate(probationPeriod uint64, cacheSize uint64) (*UnproductiveDelegate, error) { if probationPeriod > cacheSize { diff --git a/state/factory/erigonstore/registry.go b/state/factory/erigonstore/registry.go index ce50dc8f3f..b7df0b71c1 100644 --- a/state/factory/erigonstore/registry.go +++ b/state/factory/erigonstore/registry.go @@ -6,6 +6,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/iotexproject/iotex-core/v2/action/protocol/poll" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking" + "github.com/iotexproject/iotex-core/v2/action/protocol/vote" "github.com/iotexproject/iotex-core/v2/pkg/util/assertions" "github.com/iotexproject/iotex-core/v2/state" "github.com/iotexproject/iotex-core/v2/systemcontracts" @@ -25,12 +28,25 @@ var ( // ObjectStorageRegistry is a registry for object storage type ObjectStorageRegistry struct { contracts map[string]map[reflect.Type]int + fallback map[string]int } func init() { - assertions.MustNoError(storageRegistry.RegisterAccount(state.AccountKVNamespace, &state.Account{})) - assertions.MustNoError(storageRegistry.RegisterPollCandidateList(state.SystemNamespace, &state.CandidateList{})) - assertions.MustNoError(storageRegistry.RegisterPollLegacyCandidateList(state.AccountKVNamespace, &state.CandidateList{})) + assertions.MustNoError(storageRegistry.RegisterNamespace(state.AccountKVNamespace, RewardingContractV1Index)) + assertions.MustNoError(storageRegistry.RegisterNamespace(state.RewardingNamespace, RewardingContractV2Index)) + assertions.MustNoError(storageRegistry.RegisterNamespace(state.CandidateNamespace, CandidatesContractIndex)) + assertions.MustNoError(storageRegistry.RegisterNamespace(state.CandsMapNamespace, CandidateMapContractIndex)) + assertions.MustNoError(storageRegistry.RegisterNamespace(state.StakingNamespace, BucketPoolContractIndex)) + + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.AccountKVNamespace, &state.Account{}, AccountIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.AccountKVNamespace, &state.CandidateList{}, PollLegacyCandidateListContractIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.SystemNamespace, &state.CandidateList{}, PollCandidateListContractIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.SystemNamespace, &vote.UnproductiveDelegate{}, PollUnproductiveDelegateContractIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.SystemNamespace, &vote.ProbationList{}, PollProbationListContractIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.SystemNamespace, &poll.BlockMeta{}, PollBlockMetaContractIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.StakingNamespace, &staking.VoteBucket{}, StakingBucketsContractIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.StakingNamespace, &staking.Endorsement{}, EndorsementContractIndex)) + assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.StakingNamespace, &staking.BucketIndices{}, BucketIndicesContractIndex)) } // GetObjectStorageRegistry returns the global object storage registry @@ -41,18 +57,15 @@ func GetObjectStorageRegistry() *ObjectStorageRegistry { func newObjectStorageRegistry() *ObjectStorageRegistry { return &ObjectStorageRegistry{ contracts: make(map[string]map[reflect.Type]int), + fallback: make(map[string]int), } } // ObjectStorage returns the object storage for the given namespace and object type func (osr *ObjectStorageRegistry) ObjectStorage(ns string, obj any, backend *contractBackend) (ObjectStorage, error) { - types, ok := osr.contracts[ns] - if !ok { - return nil, errors.Wrapf(ErrObjectStorageNotRegistered, "namespace: %s", ns) - } - contractIndex, ok := types[reflect.TypeOf(obj)] - if !ok { - return nil, errors.Wrapf(ErrObjectStorageNotRegistered, "namespace: %s, object: %T", ns, obj) + contractIndex, exist := osr.matchContractIndex(ns, obj) + if !exist { + return nil, errors.Wrapf(ErrObjectStorageNotRegistered, "namespace: %s, type: %T", ns, obj) } // TODO: cache storage switch systemContractTypes[contractIndex] { @@ -63,7 +76,7 @@ func (osr *ObjectStorageRegistry) ObjectStorage(ns string, obj any, backend *con ) case namespaceStorageContractType: contractAddr := systemContracts[contractIndex].Address - contract, err := systemcontracts.NewGenericStorageContract(common.BytesToAddress(contractAddr.Bytes()[:]), backend, common.Address(systemContractCreatorAddr)) + contract, err := systemcontracts.NewNamespaceStorageContractWrapper(common.BytesToAddress(contractAddr.Bytes()[:]), backend, common.Address(systemContractCreatorAddr), ns) if err != nil { return nil, err } @@ -78,82 +91,30 @@ func (osr *ObjectStorageRegistry) ObjectStorage(ns string, obj any, backend *con } } -// RegisterAccount registers an account object storage -func (osr *ObjectStorageRegistry) RegisterAccount(ns string, obj any) error { - return osr.register(ns, obj, AccountIndex) -} - -// RegisterStakingBuckets registers a staking buckets object storage -func (osr *ObjectStorageRegistry) RegisterStakingBuckets(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, StakingBucketsContractIndex) -} - -// RegisterBucketPool registers a bucket pool object storage -func (osr *ObjectStorageRegistry) RegisterBucketPool(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, BucketPoolContractIndex) -} - -// RegisterBucketIndices registers a bucket indices object storage -func (osr *ObjectStorageRegistry) RegisterBucketIndices(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, BucketIndicesContractIndex) -} - -// RegisterEndorsement registers an endorsement object storage -func (osr *ObjectStorageRegistry) RegisterEndorsement(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, EndorsementContractIndex) -} - -// RegisterCandidateMap registers a candidate map object storage -func (osr *ObjectStorageRegistry) RegisterCandidateMap(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, CandidateMapContractIndex) -} - -// RegisterCandidates registers a candidates object storage -func (osr *ObjectStorageRegistry) RegisterCandidates(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, CandidatesContractIndex) -} - -// RegisterPollCandidateList registers a poll candidate list object storage -func (osr *ObjectStorageRegistry) RegisterPollCandidateList(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, PollCandidateListContractIndex) -} - -// RegisterPollLegacyCandidateList registers a poll legacy candidate list object storage -func (osr *ObjectStorageRegistry) RegisterPollLegacyCandidateList(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, PollLegacyCandidateListContractIndex) -} - -// RegisterPollProbationList registers a poll probation list object storage -func (osr *ObjectStorageRegistry) RegisterPollProbationList(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, PollProbationListContractIndex) -} - -// RegisterPollUnproductiveDelegate registers a poll unproductive delegate object storage -func (osr *ObjectStorageRegistry) RegisterPollUnproductiveDelegate(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, PollUnproductiveDelegateContractIndex) -} - -// RegisterPollBlockMeta registers a poll block meta object storage -func (osr *ObjectStorageRegistry) RegisterPollBlockMeta(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, PollBlockMetaContractIndex) -} - -// RegisterRewardingV1 registers a rewarding v1 object storage -func (osr *ObjectStorageRegistry) RegisterRewardingV1(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, RewardingContractV1Index) -} - -// RegisterRewardingV2 registers a rewarding v2 object storage -func (osr *ObjectStorageRegistry) RegisterRewardingV2(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, RewardingContractV2Index) +// RegisterObjectStorage registers a generic object storage +func (osr *ObjectStorageRegistry) RegisterObjectStorage(ns string, obj any, index int) error { + if index < AccountIndex || index >= SystemContractCount { + return errors.Errorf("invalid system contract index %d", index) + } + return osr.register(ns, obj, index) } -// RegisterStakingView registers a staking view object storage -func (osr *ObjectStorageRegistry) RegisterStakingView(ns string, obj systemcontracts.GenericValueContainer) error { - return osr.register(ns, obj, StakingViewContractIndex) +// RegisterNamespace registers a namespace object storage +func (osr *ObjectStorageRegistry) RegisterNamespace(ns string, index int) error { + if index < AccountIndex || index >= SystemContractCount { + return errors.Errorf("invalid system contract index %d", index) + } + return osr.register(ns, nil, index) } func (osr *ObjectStorageRegistry) register(ns string, obj any, index int) error { + if obj == nil { + if _, exists := osr.fallback[ns]; exists { + return errors.Wrapf(ErrObjectStorageAlreadyRegistered, "registered: %v", osr.fallback[ns]) + } + osr.fallback[ns] = index + return nil + } types, ok := osr.contracts[ns] if !ok { osr.contracts[ns] = make(map[reflect.Type]int) @@ -165,3 +126,17 @@ func (osr *ObjectStorageRegistry) register(ns string, obj any, index int) error types[reflect.TypeOf(obj)] = index return nil } + +func (osr *ObjectStorageRegistry) matchContractIndex(ns string, obj any) (int, bool) { + if obj != nil { + types, ok := osr.contracts[ns] + if ok { + index, exist := types[reflect.TypeOf(obj)] + if exist { + return index, true + } + } + } + index, exist := osr.fallback[ns] + return index, exist +} diff --git a/state/factory/workingsetstore_test.go b/state/factory/workingsetstore_test.go index de104e6e5b..098cea7884 100644 --- a/state/factory/workingsetstore_test.go +++ b/state/factory/workingsetstore_test.go @@ -52,7 +52,7 @@ func TestStateDBWorkingSetStore(t *testing.T) { var value valueBytes err := store.GetObject(namespace, key1, &value) require.Error(err) - require.NoError(store.DeleteObject(namespace, key1, &value)) + require.NoError(store.DeleteObject(namespace, key1, nil)) require.NoError(store.PutObject(namespace, key1, &value1)) var valueInStore valueBytes err = store.GetObject(namespace, key1, &valueInStore) @@ -88,7 +88,7 @@ func TestStateDBWorkingSetStore(t *testing.T) { require.Equal("e1f83be0a44ae601061724990036b8a40edbf81cffc639657c9bb2c5d384defa", hex.EncodeToString(h[:])) }) sn3 := store.Snapshot() - require.NoError(store.DeleteObject(namespace, key1, &valueInStore)) + require.NoError(store.DeleteObject(namespace, key1, nil)) err = store.GetObject(namespace, key1, &valueInStore) require.Error(err) iter, err = store.States(namespace, &valueInStore, [][]byte{key1, key2, key3}) diff --git a/systemcontracts/namespace_storage_wrapper.go b/systemcontracts/namespace_storage_wrapper.go index 2b957cfd27..c994ced1cc 100644 --- a/systemcontracts/namespace_storage_wrapper.go +++ b/systemcontracts/namespace_storage_wrapper.go @@ -65,13 +65,13 @@ func (ns *NamespaceStorageContractWrapper) BatchPut(keys [][]byte, values []Name } // List retrieves all stored data in a namespace with pagination -func (ns *NamespaceStorageContractWrapper) List(offset, limit *big.Int) (*NamespaceListResult, error) { - return ns.contract.List(ns.ns, offset, limit) +func (ns *NamespaceStorageContractWrapper) List(offset, limit uint64) (*NamespaceListResult, error) { + return ns.contract.List(ns.ns, big.NewInt(int64(offset)), big.NewInt(int64(limit))) } // ListKeys retrieves all keys in a namespace with pagination -func (ns *NamespaceStorageContractWrapper) ListKeys(offset, limit *big.Int) (*NamespaceListKeysResult, error) { - return ns.contract.ListKeys(ns.ns, offset, limit) +func (ns *NamespaceStorageContractWrapper) ListKeys(offset, limit uint64) (*NamespaceListKeysResult, error) { + return ns.contract.ListKeys(ns.ns, big.NewInt(int64(offset)), big.NewInt(int64(limit))) } // Count returns the number of items in the namespace