Skip to content

Commit 8458a59

Browse files
committed
store contract buckets in erigondb
1 parent 6563074 commit 8458a59

File tree

8 files changed

+138
-21
lines changed

8 files changed

+138
-21
lines changed

action/protocol/staking/contractstaking/bucket.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"math/big"
55

66
"github.com/iotexproject/iotex-address/address"
7-
"github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb"
87
"github.com/pkg/errors"
98
"google.golang.org/protobuf/proto"
9+
10+
"github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb"
11+
"github.com/iotexproject/iotex-core/v2/systemcontracts"
1012
)
1113

1214
type (
@@ -113,3 +115,17 @@ func (b *Bucket) Clone() *Bucket {
113115
Muted: b.Muted,
114116
}
115117
}
118+
119+
// Encode encodes the bucket into a GenericValue
120+
func (b *Bucket) Encode() (systemcontracts.GenericValue, error) {
121+
data, err := b.Serialize()
122+
if err != nil {
123+
return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize bucket")
124+
}
125+
return systemcontracts.GenericValue{PrimaryData: data}, nil
126+
}
127+
128+
// Decode decodes the bucket from a GenericValue
129+
func (b *Bucket) Decode(gv systemcontracts.GenericValue) error {
130+
return b.Deserialize(gv.PrimaryData)
131+
}

action/protocol/staking/contractstaking/bucket_type.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package contractstaking
33
import (
44
"math/big"
55

6-
"github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb"
76
"github.com/pkg/errors"
87
"google.golang.org/protobuf/proto"
8+
9+
"github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb"
10+
"github.com/iotexproject/iotex-core/v2/systemcontracts"
911
)
1012

1113
type (
@@ -65,3 +67,17 @@ func (bt *BucketType) Clone() *BucketType {
6567
ActivatedAt: bt.ActivatedAt,
6668
}
6769
}
70+
71+
// Encode encodes the bucket type into a GenericValue
72+
func (bt *BucketType) Encode() (systemcontracts.GenericValue, error) {
73+
data, err := bt.Serialize()
74+
if err != nil {
75+
return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize bucket type")
76+
}
77+
return systemcontracts.GenericValue{PrimaryData: data}, nil
78+
}
79+
80+
// Decode decodes the bucket type from a GenericValue
81+
func (bt *BucketType) Decode(gv systemcontracts.GenericValue) error {
82+
return bt.Deserialize(gv.PrimaryData)
83+
}

action/protocol/staking/contractstaking/contract.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package contractstaking
22

33
import (
4-
"github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb"
54
"github.com/pkg/errors"
65
"google.golang.org/protobuf/proto"
6+
7+
"github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb"
8+
"github.com/iotexproject/iotex-core/v2/systemcontracts"
79
)
810

911
// StakingContract represents the staking contract in the system
@@ -50,3 +52,17 @@ func (sc *StakingContract) Deserialize(b []byte) error {
5052
*sc = *loaded
5153
return nil
5254
}
55+
56+
// Encode encodes the staking contract into a GenericValue
57+
func (sc *StakingContract) Encode() (systemcontracts.GenericValue, error) {
58+
data, err := sc.Serialize()
59+
if err != nil {
60+
return systemcontracts.GenericValue{}, errors.Wrap(err, "failed to serialize staking contract")
61+
}
62+
return systemcontracts.GenericValue{PrimaryData: data}, nil
63+
}
64+
65+
// Decode decodes the staking contract from a GenericValue
66+
func (sc *StakingContract) Decode(gv systemcontracts.GenericValue) error {
67+
return sc.Deserialize(gv.PrimaryData)
68+
}

action/protocol/staking/contractstaking/statereader.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ package contractstaking
33
import (
44
"fmt"
55

6+
"github.com/pkg/errors"
7+
68
"github.com/iotexproject/iotex-core/v2/action/protocol"
79
"github.com/iotexproject/iotex-core/v2/action/protocol/staking/stakingpb"
810
"github.com/iotexproject/iotex-core/v2/pkg/util/byteutil"
911
"github.com/iotexproject/iotex-core/v2/state"
10-
"github.com/pkg/errors"
1112

1213
"github.com/iotexproject/iotex-address/address"
1314
)
@@ -25,11 +26,11 @@ func NewStateReader(sr protocol.StateReader) *ContractStakingStateReader {
2526
}
2627

2728
func contractNamespaceOption(contractAddr address.Address) protocol.StateOption {
28-
return protocol.NamespaceOption(fmt.Sprintf("cs_bucket_%x", contractAddr.Bytes()))
29+
return protocol.NamespaceOption(fmt.Sprintf("%s%x", state.ContractStakingBucketNamespacePrefix, contractAddr.Bytes()))
2930
}
3031

3132
func bucketTypeNamespaceOption(contractAddr address.Address) protocol.StateOption {
32-
return protocol.NamespaceOption(fmt.Sprintf("cs_bucket_type_%x", contractAddr.Bytes()))
33+
return protocol.NamespaceOption(fmt.Sprintf("%s%x", state.ContractStakingBucketTypeNamespacePrefix, contractAddr.Bytes()))
3334
}
3435

3536
func contractKeyOption(contractAddr address.Address) protocol.StateOption {
@@ -42,7 +43,7 @@ func bucketIDKeyOption(bucketID uint64) protocol.StateOption {
4243

4344
// metaNamespaceOption is the namespace for meta information (e.g., total number of buckets).
4445
func metaNamespaceOption() protocol.StateOption {
45-
return protocol.NamespaceOption("staking_contract_meta")
46+
return protocol.NamespaceOption(state.StakingContractMetaNamespace)
4647
}
4748

4849
func (r *ContractStakingStateReader) contract(contractAddr address.Address) (*StakingContract, error) {

action/protocol/staking/protocol.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,9 @@ func (p *Protocol) HandleReceipt(ctx context.Context, elp action.Envelope, sm pr
683683
if err != nil {
684684
return err
685685
}
686-
return v.(*viewData).contractsStake.Handle(ctx, receipt)
686+
if err := v.(*viewData).contractsStake.Handle(ctx, receipt); err != nil {
687+
return err
688+
}
687689
}
688690
handler, err := newNFTBucketEventHandler(sm, func(bucket *contractstaking.Bucket, height uint64) *big.Int {
689691
vb := p.convertToVoteBucket(bucket, height)

state/factory/erigonstore/registry.go

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package erigonstore
22

33
import (
44
"reflect"
5+
"strings"
56

67
"github.com/ethereum/go-ethereum/common"
78
"github.com/pkg/errors"
@@ -28,7 +29,8 @@ var (
2829
// ObjectStorageRegistry is a registry for object storage
2930
type ObjectStorageRegistry struct {
3031
contracts map[string]map[reflect.Type]int
31-
fallback map[string]int
32+
ns map[string]int
33+
nsPrefix map[string]int
3234
}
3335

3436
func init() {
@@ -38,7 +40,9 @@ func init() {
3840
assertions.MustNoError(storageRegistry.RegisterNamespace(state.CandsMapNamespace, CandidateMapContractIndex))
3941
assertions.MustNoError(storageRegistry.RegisterNamespace(state.StakingNamespace, BucketPoolContractIndex))
4042
assertions.MustNoError(storageRegistry.RegisterNamespace(state.StakingViewNamespace, StakingViewContractIndex))
41-
assertions.MustNoError(storageRegistry.RegisterNamespace(state.StakingNamespace, BucketPoolContractIndex))
43+
assertions.MustNoError(storageRegistry.RegisterNamespace(state.StakingContractMetaNamespace, StakingViewContractIndex))
44+
assertions.MustNoError(storageRegistry.RegisterNamespacePrefix(state.ContractStakingBucketNamespacePrefix, StakingViewContractIndex))
45+
assertions.MustNoError(storageRegistry.RegisterNamespacePrefix(state.ContractStakingBucketTypeNamespacePrefix, StakingViewContractIndex))
4246

4347
assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.AccountKVNamespace, &state.Account{}, AccountIndex))
4448
assertions.MustNoError(storageRegistry.RegisterObjectStorage(state.AccountKVNamespace, &state.CandidateList{}, PollLegacyCandidateListContractIndex))
@@ -59,7 +63,8 @@ func GetObjectStorageRegistry() *ObjectStorageRegistry {
5963
func newObjectStorageRegistry() *ObjectStorageRegistry {
6064
return &ObjectStorageRegistry{
6165
contracts: make(map[string]map[reflect.Type]int),
62-
fallback: make(map[string]int),
66+
ns: make(map[string]int),
67+
nsPrefix: make(map[string]int),
6368
}
6469
}
6570

@@ -109,12 +114,28 @@ func (osr *ObjectStorageRegistry) RegisterNamespace(ns string, index int) error
109114
return osr.register(ns, nil, index)
110115
}
111116

117+
// RegisterNamespacePrefix registers a namespace prefix object storage
118+
func (osr *ObjectStorageRegistry) RegisterNamespacePrefix(prefix string, index int) error {
119+
if index < AccountIndex || index >= SystemContractCount {
120+
return errors.Errorf("invalid system contract index %d", index)
121+
}
122+
return osr.registerPrefix(prefix, index)
123+
}
124+
125+
func (osr *ObjectStorageRegistry) registerPrefix(ns string, index int) error {
126+
if _, exists := osr.nsPrefix[ns]; exists {
127+
return errors.Wrapf(ErrObjectStorageAlreadyRegistered, "registered: %v", osr.nsPrefix[ns])
128+
}
129+
osr.nsPrefix[ns] = index
130+
return nil
131+
}
132+
112133
func (osr *ObjectStorageRegistry) register(ns string, obj any, index int) error {
113134
if obj == nil {
114-
if _, exists := osr.fallback[ns]; exists {
115-
return errors.Wrapf(ErrObjectStorageAlreadyRegistered, "registered: %v", osr.fallback[ns])
135+
if _, exists := osr.ns[ns]; exists {
136+
return errors.Wrapf(ErrObjectStorageAlreadyRegistered, "registered: %v", osr.ns[ns])
116137
}
117-
osr.fallback[ns] = index
138+
osr.ns[ns] = index
118139
return nil
119140
}
120141
types, ok := osr.contracts[ns]
@@ -130,6 +151,7 @@ func (osr *ObjectStorageRegistry) register(ns string, obj any, index int) error
130151
}
131152

132153
func (osr *ObjectStorageRegistry) matchContractIndex(ns string, obj any) (int, bool) {
154+
// object specific storage
133155
if obj != nil {
134156
types, ok := osr.contracts[ns]
135157
if ok {
@@ -139,6 +161,16 @@ func (osr *ObjectStorageRegistry) matchContractIndex(ns string, obj any) (int, b
139161
}
140162
}
141163
}
142-
index, exist := osr.fallback[ns]
143-
return index, exist
164+
// namespace specific storage
165+
index, exist := osr.ns[ns]
166+
if exist {
167+
return index, true
168+
}
169+
// namespace prefix specific storage
170+
for prefix, index := range osr.nsPrefix {
171+
if strings.HasPrefix(ns, prefix) {
172+
return index, true
173+
}
174+
}
175+
return 0, false
144176
}

state/factory/statedb.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"slices"
1212
"strconv"
13+
"strings"
1314
"sync"
1415
"time"
1516

@@ -283,7 +284,7 @@ func (sdb *stateDB) createWorkingSetStore(ctx context.Context, height uint64, kv
283284
flusher, err := db.NewKVStoreFlusher(
284285
kvstore,
285286
batch.NewCachedBatch(),
286-
sdb.flusherOptions(!g.IsEaster(height))...,
287+
sdb.flusherOptions(!g.IsEaster(height), g.IsToBeEnabled(height))...,
287288
)
288289
if err != nil {
289290
return nil, err
@@ -559,7 +560,7 @@ func (sdb *stateDB) StateReaderAt(blkHeight uint64, blkHash hash.Hash256) (proto
559560
// private trie constructor functions
560561
//======================================
561562

562-
func (sdb *stateDB) flusherOptions(preEaster bool) []db.KVStoreFlusherOption {
563+
func (sdb *stateDB) flusherOptions(preEaster, storeContractStaking bool) []db.KVStoreFlusherOption {
563564
opts := []db.KVStoreFlusherOption{
564565
db.SerializeOption(func(wi *batch.WriteInfo) []byte {
565566
if preEaster {
@@ -568,19 +569,43 @@ func (sdb *stateDB) flusherOptions(preEaster bool) []db.KVStoreFlusherOption {
568569
return wi.Serialize()
569570
}),
570571
}
571-
serializeFilterNs := []string{state.StakingViewNamespace}
572+
var (
573+
serializeFilterNs = []string{state.StakingViewNamespace}
574+
serializeFilterNsPrefixes = []string{}
575+
flushFilterNs = []string{state.StakingViewNamespace}
576+
flushFilterNsPrefixes = []string{}
577+
)
572578
if preEaster {
573579
serializeFilterNs = append(serializeFilterNs, evm.CodeKVNameSpace, staking.CandsMapNS)
574580
}
581+
if !storeContractStaking {
582+
serializeFilterNs = append(serializeFilterNs, state.StakingContractMetaNamespace)
583+
serializeFilterNsPrefixes = append(serializeFilterNsPrefixes,
584+
state.ContractStakingBucketNamespacePrefix,
585+
state.ContractStakingBucketTypeNamespacePrefix,
586+
)
587+
flushFilterNs = append(flushFilterNs, state.StakingContractMetaNamespace)
588+
flushFilterNsPrefixes = append(flushFilterNsPrefixes,
589+
state.ContractStakingBucketNamespacePrefix,
590+
state.ContractStakingBucketTypeNamespacePrefix,
591+
)
592+
}
575593
opts = append(opts,
576594
db.FlushTranslateOption(func(wi *batch.WriteInfo) *batch.WriteInfo {
577-
if wi.Namespace() == state.StakingViewNamespace {
595+
if slices.Contains(flushFilterNs, wi.Namespace()) ||
596+
slices.ContainsFunc(flushFilterNsPrefixes, func(prefix string) bool {
597+
return strings.HasPrefix(wi.Namespace(), prefix)
598+
}) {
599+
// skip flushing the write
578600
return nil
579601
}
580602
return wi
581603
}),
582604
db.SerializeFilterOption(func(wi *batch.WriteInfo) bool {
583-
return slices.Contains(serializeFilterNs, wi.Namespace())
605+
return slices.Contains(serializeFilterNs, wi.Namespace()) ||
606+
slices.ContainsFunc(serializeFilterNsPrefixes, func(prefix string) bool {
607+
return strings.HasPrefix(wi.Namespace(), prefix)
608+
})
584609
}),
585610
)
586611
return opts

state/tables.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ const (
4242
// - "voteview" + <contractAddress> --> CandidateVotes
4343
StakingViewNamespace = "StakingView"
4444

45+
// ContractStakingBucketNamespacePrefix is the namespace to store staking contract buckets
46+
// - <contractAddress> --> <bucketID> --> Bucket
47+
ContractStakingBucketNamespacePrefix = "cs_bucket_"
48+
// ContractStakingBucketTypeNamespacePrefix is the namespace to store staking contract bucket types
49+
// - <contractAddress> --> <typeID> --> BucketType
50+
ContractStakingBucketTypeNamespacePrefix = "cs_bucket_type_"
51+
// StakingContractMetaNamespace is the namespace to store staking contract meta information
52+
StakingContractMetaNamespace = "staking_contract_meta"
53+
4554
// CandidateNamespace is the namespace to store candidate information
4655
// - <ID> --> Candidate
4756
CandidateNamespace = "Candidate"

0 commit comments

Comments
 (0)