Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion action/protocol/execution/evm/contract_adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func newContractAdapter(addr hash.Hash160, account *state.Account, sm protocol.S
if err != nil {
return nil, errors.Wrap(err, "failed to create contract")
}
v2, err := newContractErigon(addr, account, intra)
v2, err := newContractErigon(addr, account.Clone(), intra, sm)
if err != nil {
return nil, errors.Wrap(err, "failed to create contractV2")
}
Expand Down
21 changes: 14 additions & 7 deletions action/protocol/execution/evm/contract_erigon.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,25 @@ import (
"github.com/iotexproject/go-pkgs/hash"
"github.com/pkg/errors"

"github.com/iotexproject/iotex-core/v2/action/protocol"
"github.com/iotexproject/iotex-core/v2/db/trie"
"github.com/iotexproject/iotex-core/v2/pkg/log"
"github.com/iotexproject/iotex-core/v2/state"
)

type contractErigon struct {
*state.Account
intra *erigonstate.IntraBlockState
sr protocol.StateReader
addr hash.Hash160
}

func newContractErigon(addr hash.Hash160, account *state.Account, intra *erigonstate.IntraBlockState) (Contract, error) {
func newContractErigon(addr hash.Hash160, account *state.Account, intra *erigonstate.IntraBlockState, sr protocol.StateReader) (Contract, error) {
c := &contractErigon{
Account: account,
intra: intra,
addr: addr,
sr: sr,
}
return c, nil
}
Expand All @@ -32,14 +36,16 @@ func (c *contractErigon) GetCommittedState(key hash.Hash256) ([]byte, error) {
k := libcommon.Hash(key)
v := uint256.NewInt(0)
c.intra.GetCommittedState(libcommon.Address(c.addr), &k, v)
return v.Bytes(), nil
h := hash.BytesToHash256(v.Bytes())
return h[:], nil
}

func (c *contractErigon) GetState(key hash.Hash256) ([]byte, error) {
k := libcommon.Hash(key)
v := uint256.NewInt(0)
c.intra.GetState(libcommon.Address(c.addr), &k, v)
return v.Bytes(), nil
h := hash.BytesToHash256(v.Bytes())
return h[:], nil
}

func (c *contractErigon) SetState(key hash.Hash256, value []byte) error {
Expand All @@ -58,10 +64,10 @@ func (c *contractErigon) SetCode(hash hash.Hash256, code []byte) {

func (c *contractErigon) SelfState() *state.Account {
acc := &state.Account{}
acc.SetPendingNonce(c.intra.GetNonce(libcommon.Address(c.addr)))
acc.AddBalance(c.intra.GetBalance(libcommon.Address(c.addr)).ToBig())
codeHash := c.intra.GetCodeHash(libcommon.Address(c.addr))
acc.CodeHash = codeHash[:]
_, err := c.sr.State(acc, protocol.LegacyKeyOption(c.addr), protocol.ErigonStoreOnlyOption())
if err != nil {
log.S().Panicf("failed to load account %x: %v", c.addr, err)
}
return acc
}

Expand All @@ -83,5 +89,6 @@ func (c *contractErigon) Snapshot() Contract {
Account: c.Account.Clone(),
intra: c.intra,
addr: c.addr,
sr: c.sr,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func NewErigonStateDBAdapterDryrun(adapter *StateDBAdapter,
) *ErigonStateDBAdapterDryrun {
a := NewErigonStateDBAdapter(adapter, intra)
adapter.newContract = func(addr hash.Hash160, account *state.Account) (Contract, error) {
return newContractErigon(addr, account, intra)
return newContractErigon(addr, account, intra, adapter.sm)
}
return &ErigonStateDBAdapterDryrun{
ErigonStateDBAdapter: a,
Expand Down
57 changes: 57 additions & 0 deletions action/protocol/lazyviews.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package protocol

import "context"

type (
lazyViews struct {
v Views
loader func() Views
}
)

// NewLazyViews creates a lazy-loaded Views
func NewLazyViews(loader func() Views) Views {
return &lazyViews{
loader: loader,
}
}

func (lv *lazyViews) ensureLoaded() {
if lv.v == nil {
lv.v = lv.loader()
}
}

func (lv *lazyViews) Snapshot() int {
if lv.v == nil {
return 0
}
return lv.v.Snapshot()
}

func (lv *lazyViews) Revert(id int) error {
if lv.v == nil {
return nil
}
return lv.v.Revert(id)
}

func (lv *lazyViews) Fork() Views {
lv.ensureLoaded()
return lv.v.Fork()
}

func (lv *lazyViews) Commit(ctx context.Context, sm StateManager) error {
lv.ensureLoaded()
return lv.v.Commit(ctx, sm)
}

func (lv *lazyViews) Read(name string) (View, error) {
lv.ensureLoaded()
return lv.v.Read(name)
}

func (lv *lazyViews) Write(name string, v View) {
lv.ensureLoaded()
lv.v.Write(name, v)
}
30 changes: 19 additions & 11 deletions action/protocol/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,30 @@ type (
}

// Views stores the view for all protocols
Views struct {
Views interface {
Snapshot() int
Revert(id int) error
Fork() Views
Commit(ctx context.Context, sm StateManager) error
Read(name string) (View, error)
Write(name string, v View)
}
views struct {
snapshotID int
snapshots map[int]map[string]int
vm map[string]View
}
)

func NewViews() *Views {
return &Views{
func NewViews() Views {
return &views{
snapshotID: 0,
snapshots: make(map[int]map[string]int),
vm: make(map[string]View),
}
}

func (views *Views) Snapshot() int {
func (views *views) Snapshot() int {
views.snapshotID++
views.snapshots[views.snapshotID] = make(map[string]int)
keys := make([]string, 0, len(views.vm))
Expand All @@ -148,7 +156,7 @@ func (views *Views) Snapshot() int {
return views.snapshotID
}

func (views *Views) Revert(id int) error {
func (views *views) Revert(id int) error {
if id > views.snapshotID || id < 0 {
return errors.Errorf("invalid snapshot id %d, max id is %d", id, views.snapshotID)
}
Expand All @@ -165,15 +173,15 @@ func (views *Views) Revert(id int) error {
return nil
}

func (views *Views) Fork() *Views {
fork := NewViews()
for key, view := range views.vm {
func (viewss *views) Fork() Views {
fork := NewViews().(*views)
for key, view := range viewss.vm {
fork.vm[key] = view.Fork()
}
return fork
}

func (views *Views) Commit(ctx context.Context, sm StateManager) error {
func (views *views) Commit(ctx context.Context, sm StateManager) error {
for _, view := range views.vm {
if err := view.Commit(ctx, sm); err != nil {
return err
Expand All @@ -182,14 +190,14 @@ func (views *Views) Commit(ctx context.Context, sm StateManager) error {
return nil
}

func (views *Views) Read(name string) (View, error) {
func (views *views) Read(name string) (View, error) {
if v, hit := views.vm[name]; hit {
return v, nil
}
return nil, ErrNoName
}

func (views *Views) Write(name string, v View) {
func (views *views) Write(name string, v View) {
views.vm[name] = v
}

Expand Down
2 changes: 1 addition & 1 deletion action/protocol/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (r *Registry) all() []Protocol {
}

// StartAll starts all protocols which are startable
func (r *Registry) StartAll(ctx context.Context, sr StateReader) (*Views, error) {
func (r *Registry) StartAll(ctx context.Context, sr StateReader) (Views, error) {
if r == nil {
return nil, nil
}
Expand Down
43 changes: 40 additions & 3 deletions action/protocol/rewarding/fund.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"github.com/iotexproject/iotex-core/v2/systemcontracts"
)

type Fund = fund

// fund stores the balance of the rewarding fund. The difference between total and available balance should be
// equal to the unclaimed balance in all reward accounts
type fund struct {
Expand Down Expand Up @@ -59,17 +61,52 @@ func (f *fund) Deserialize(data []byte) error {
}

func (f *fund) Encode() (systemcontracts.GenericValue, error) {
data, err := f.Serialize()
d1, err := proto.Marshal(&rewardingpb.Fund{
TotalBalance: f.totalBalance.String(),
})
if err != nil {
return systemcontracts.GenericValue{}, err
}
d2, err := proto.Marshal(&rewardingpb.Fund{
UnclaimedBalance: f.unclaimedBalance.String(),
})
if err != nil {
return systemcontracts.GenericValue{}, err
}
return systemcontracts.GenericValue{
AuxiliaryData: data,
PrimaryData: d1,
SecondaryData: d2,
}, nil
}

func (f *fund) Decode(v systemcontracts.GenericValue) error {
return f.Deserialize(v.AuxiliaryData)
gen1 := rewardingpb.Fund{}
if err := proto.Unmarshal(v.PrimaryData, &gen1); err != nil {
return err
}
var totalBalance = big.NewInt(0)
if len(gen1.TotalBalance) > 0 {
b, ok := new(big.Int).SetString(gen1.TotalBalance, 10)
if !ok {
return errors.Errorf("failed to set total balance from string: %s", gen1.TotalBalance)
}
totalBalance = b
}
gen2 := rewardingpb.Fund{}
if err := proto.Unmarshal(v.SecondaryData, &gen2); err != nil {
return err
}
var unclaimedBalance = big.NewInt(0)
if len(gen2.UnclaimedBalance) > 0 {
b, ok := new(big.Int).SetString(gen2.UnclaimedBalance, 10)
if !ok {
return errors.Errorf("failed to set unclaimed balance from string: %s", gen2.UnclaimedBalance)
}
unclaimedBalance = b
}
f.totalBalance = totalBalance
f.unclaimedBalance = unclaimedBalance
return nil
}

// Deposit deposits token into the rewarding fund
Expand Down
36 changes: 32 additions & 4 deletions action/protocol/rewarding/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
accountutil "github.com/iotexproject/iotex-core/v2/action/protocol/account/util"
"github.com/iotexproject/iotex-core/v2/action/protocol/rolldpos"
"github.com/iotexproject/iotex-core/v2/blockchain/genesis"
"github.com/iotexproject/iotex-core/v2/pkg/enc"
"github.com/iotexproject/iotex-core/v2/pkg/log"
"github.com/iotexproject/iotex-core/v2/state"
)
Expand Down Expand Up @@ -102,6 +103,13 @@ func FindProtocol(registry *protocol.Registry) *Protocol {
func (p *Protocol) CreatePreStates(ctx context.Context, sm protocol.StateManager) error {
g := genesis.MustExtractGenesisContext(ctx)
blkCtx := protocol.MustGetBlockCtx(ctx)
// set current block reward not granted for erigon db
var indexBytes [8]byte
enc.MachineEndian.PutUint64(indexBytes[:], blkCtx.BlockHeight)
err := p.deleteState(ctx, sm, append(_blockRewardHistoryKeyPrefix, indexBytes[:]...), &rewardHistory{}, protocol.ErigonStoreOnlyOption())
if err != nil && !errors.Is(err, state.ErrErigonStoreNotSupported) {
return errors.Wrap(err, "failed to delete block reward history for erigon store")
}
switch blkCtx.BlockHeight {
case g.AleutianBlockHeight:
return p.SetReward(ctx, sm, g.AleutianEpochReward(), false)
Expand Down Expand Up @@ -348,10 +356,11 @@ func (p *Protocol) putState(ctx context.Context, sm protocol.StateManager, key [
return p.putStateV1(sm, key, value)
}

func (p *Protocol) putStateV1(sm protocol.StateManager, key []byte, value interface{}) error {
func (p *Protocol) putStateV1(sm protocol.StateManager, key []byte, value interface{}, opts ...protocol.StateOption) error {
orgKey := append(p.keyPrefix, key...)
keyHash := hash.Hash160b(orgKey)
_, err := sm.PutState(value, protocol.LegacyKeyOption(keyHash), protocol.ErigonStoreKeyOption(orgKey))
opts = append(opts, protocol.LegacyKeyOption(keyHash), protocol.ErigonStoreKeyOption(orgKey))
_, err := sm.PutState(value, opts...)
return err
}

Expand All @@ -361,10 +370,29 @@ func (p *Protocol) putStateV2(sm protocol.StateManager, key []byte, value interf
return err
}

func (p *Protocol) deleteStateV1(sm protocol.StateManager, key []byte, obj any) error {
func (p *Protocol) deleteState(ctx context.Context, sm protocol.StateManager, key []byte, obj any, opts ...protocol.StateOption) error {
if useV2Storage(ctx) {
return p.deleteStateV2(sm, key, obj, opts...)
}
return p.deleteStateV1(sm, key, obj, opts...)
}

func (p *Protocol) deleteStateV1(sm protocol.StateManager, key []byte, obj any, opts ...protocol.StateOption) error {
orgKey := append(p.keyPrefix, key...)
keyHash := hash.Hash160b(orgKey)
_, err := sm.DelState(protocol.LegacyKeyOption(keyHash), protocol.ObjectOption(obj), protocol.ErigonStoreKeyOption(orgKey))
opt := append(opts, protocol.LegacyKeyOption(keyHash), protocol.ObjectOption(obj), protocol.ErigonStoreKeyOption(orgKey))
_, err := sm.DelState(opt...)
if errors.Cause(err) == state.ErrStateNotExist {
// don't care if not exist
return nil
}
return err
}

func (p *Protocol) deleteStateV2(sm protocol.StateManager, key []byte, value any, opts ...protocol.StateOption) error {
k := append(p.keyPrefix, key...)
opt := append(opts, protocol.KeyOption(k), protocol.ObjectOption(value), protocol.NamespaceOption(_v2RewardingNamespace))
_, err := sm.DelState(opt...)
if errors.Cause(err) == state.ErrStateNotExist {
// don't care if not exist
return nil
Expand Down
11 changes: 11 additions & 0 deletions action/protocol/rewarding/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,14 @@ func TestProtocol_Handle(t *testing.T) {
}).AnyTimes()
sm.EXPECT().Snapshot().Return(1).AnyTimes()
sm.EXPECT().Revert(gomock.Any()).Return(nil).AnyTimes()
sm.EXPECT().DelState(gomock.Any()).DoAndReturn(func(opts ...protocol.StateOption) (uint64, error) {
cfg, err := protocol.CreateStateConfig(opts...)
if err != nil {
return 0, err
}
cb.Delete("state", cfg.Key, "failed to delete state")
return 0, nil
}).AnyTimes()

g.Rewarding.InitBalanceStr = "1000000"
g.Rewarding.BlockRewardStr = "10"
Expand Down Expand Up @@ -656,6 +664,9 @@ func TestMigrateValue(t *testing.T) {
blkCtx := protocol.MustGetBlockCtx(ctx)
blkCtx.BlockHeight = v.height
fCtx = protocol.WithFeatureCtx(protocol.WithBlockCtx(fCtx, blkCtx))
// init storage bucket
_, err = sm.PutState(&rewardHistory{}, protocol.NamespaceOption(_v2RewardingNamespace), protocol.KeyOption([]byte("test")))
r.NoError(err)
r.NoError(p.CreatePreStates(fCtx, sm))

// verify v1 is deleted
Expand Down
Loading