Skip to content

Commit b529087

Browse files
authored
fix low gas limit for reading native staking contract (#1852)
1 parent ac62919 commit b529087

File tree

7 files changed

+288
-24
lines changed

7 files changed

+288
-24
lines changed

action/protocol/poll/nativestaking.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2019 IoTeX Foundation
1+
// Copyright (c) 2020 IoTeX Foundation
22
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
33
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
44
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
@@ -79,7 +79,7 @@ func NewNativeStaking(cm protocol.ChainManager, getTipBlockTime GetTipBlockTime)
7979
}
8080

8181
// Votes returns the votes on height
82-
func (ns *NativeStaking) Votes() (*VoteTally, time.Time, error) {
82+
func (ns *NativeStaking) Votes(correctGas bool) (*VoteTally, time.Time, error) {
8383
if ns.contract == "" {
8484
return nil, time.Time{}, ErrNoData
8585
}
@@ -97,52 +97,57 @@ func (ns *NativeStaking) Votes() (*VoteTally, time.Time, error) {
9797
limit := big.NewInt(256)
9898

9999
for {
100-
vote, err := ns.readBuckets(prevIndex, limit)
100+
vote, index, err := ns.readBuckets(prevIndex, limit, correctGas)
101101
log.L().Debug("Read native buckets from contract", zap.Int("size", len(vote)))
102102
if err == ErrEndOfData {
103103
// all data been read
104104
break
105105
}
106106
if err != nil {
107+
log.L().Error(" read native staking contract", zap.Error(err))
107108
return nil, now, err
108109
}
109110
votes.tally(vote, now)
110111
if len(vote) < int(limit.Int64()) {
111112
// all data been read
112113
break
113114
}
114-
prevIndex.Add(prevIndex, limit)
115+
prevIndex = index
115116
}
116117
return &votes, now, nil
117118
}
118119

119-
func (ns *NativeStaking) readBuckets(prevIndx, limit *big.Int) ([]*types.Bucket, error) {
120+
func (ns *NativeStaking) readBuckets(prevIndx, limit *big.Int, correctGas bool) ([]*types.Bucket, *big.Int, error) {
120121
data, err := ns.abi.Pack("getActivePyggs", prevIndx, limit)
121122
if err != nil {
122-
return nil, err
123+
return nil, nil, err
123124
}
124125

125126
// read the staking contract
126-
ex, err := action.NewExecution(ns.contract, 1, big.NewInt(0), 1000000, big.NewInt(0), data)
127+
gasLimit := uint64(1000000)
128+
if correctGas {
129+
gasLimit *= 10
130+
}
131+
ex, err := action.NewExecution(ns.contract, 1, big.NewInt(0), gasLimit, big.NewInt(0), data)
127132
if err != nil {
128-
return nil, err
133+
return nil, nil, err
129134
}
130135
data, _, err = ns.cm.ExecuteContractRead(dummyCaller, ex)
131136
if err != nil {
132-
return nil, err
137+
return nil, nil, err
133138
}
134139

135140
// decode the contract read result
136141
pygg := &pygg{}
137142
if err = ns.abi.Unpack(pygg, "getActivePyggs", data); err != nil {
138143
if err.Error() == "abi: unmarshalling empty output" {
139144
// no data in contract (one possible reason is that contract does not exist yet)
140-
return nil, ErrNoData
145+
return nil, nil, ErrNoData
141146
}
142-
return nil, err
147+
return nil, nil, err
143148
}
144149
if len(pygg.CanNames) == 0 {
145-
return nil, ErrEndOfData
150+
return nil, nil, ErrEndOfData
146151
}
147152
buckets := make([]*types.Bucket, len(pygg.CanNames))
148153
for i := range pygg.CanNames {
@@ -155,10 +160,11 @@ func (ns *NativeStaking) readBuckets(prevIndx, limit *big.Int) ([]*types.Bucket,
155160
pygg.Decays[i],
156161
)
157162
if err != nil {
158-
return nil, err
163+
return nil, nil, err
159164
}
160165
}
161-
return buckets, nil
166+
// last one of returned indexes should be used as starting index for next query
167+
return buckets, pygg.Indexes[len(pygg.Indexes)-1], nil
162168
}
163169

164170
// SetContract sets the contract address

action/protocol/poll/nativestaking_test.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
// Copyright (c) 2020 IoTeX Foundation
2+
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
3+
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
4+
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
5+
// License 2.0 that can be found in the LICENSE file.
6+
17
package poll
28

39
import (
@@ -66,7 +72,7 @@ func TestStaking(t *testing.T) {
6672
)
6773
}
6874

69-
tallies := VoteTally{
75+
tallies := &VoteTally{
7076
Candidates: make(map[[12]byte]*state.Candidate),
7177
Buckets: make([]*types.Bucket, 0),
7278
}
@@ -82,6 +88,44 @@ func TestStaking(t *testing.T) {
8288
}
8389
}
8490
require.Equal(len(buckets), len(tallies.Buckets))
91+
for i := range buckets {
92+
require.Equal(buckets[i], tallies.Buckets[i])
93+
}
94+
95+
// merge with existing data
96+
cand := state.CandidateList{
97+
&state.Candidate{
98+
CanName: []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
99+
Votes: big.NewInt(111),
100+
},
101+
&state.Candidate{
102+
CanName: []byte{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
103+
Votes: big.NewInt(111),
104+
},
105+
&state.Candidate{
106+
CanName: []byte{107, 111, 118, 97, 110, 114, 111, 98, 111, 116, 50, 56},
107+
Votes: big.NewInt(111),
108+
},
109+
&state.Candidate{
110+
CanName: []byte{107, 111, 118, 97, 110, 114, 111, 98, 111, 116, 50, 55},
111+
Votes: big.NewInt(111),
112+
},
113+
}
114+
115+
amount = big.NewInt(unit.Iotx)
116+
sc := &stakingCommittee{
117+
nativeStaking: ns,
118+
scoreThreshold: amount.Mul(amount, big.NewInt(200)),
119+
}
120+
121+
newCand := sc.mergeDelegates(cand, tallies, time.Now())
122+
require.Equal(2, len(newCand))
123+
for i := range newCand {
124+
name := cand[i].CanName
125+
require.Equal(name, newCand[i].CanName)
126+
cand[i].Votes.Add(cand[i].Votes, tallies.Candidates[to12Bytes(name)].Votes)
127+
require.Equal(cand[i].Votes, newCand[i].Votes)
128+
}
85129

86130
// test empty data from contract
87131
require.NoError(ns.abi.Unpack(pygg, "getActivePyggs", empty))

action/protocol/poll/staking_committee.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2019 IoTeX Foundation
1+
// Copyright (c) 2020 IoTeX Foundation
22
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
33
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
44
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
@@ -113,7 +113,7 @@ func (sc *stakingCommittee) DelegatesByHeight(height uint64) (state.CandidateLis
113113
if sc.nativeStaking == nil {
114114
return nil, errors.New("native staking was not set after cook height")
115115
}
116-
nativeVotes, ts, err := sc.nativeStaking.Votes()
116+
nativeVotes, ts, err := sc.nativeStaking.Votes(sc.hu.IsPost(config.Daytona, height))
117117
if err == ErrNoData {
118118
// no native staking data
119119
return sc.filterDelegates(cand), nil

blockchain/genesis/genesis.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2019 IoTeX Foundation
1+
// Copyright (c) 2020 IoTeX Foundation
22
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
33
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
44
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
@@ -53,6 +53,7 @@ func defaultConfig() Genesis {
5353
BeringBlockHeight: 1512001,
5454
CookBlockHeight: 1641601,
5555
DardanellesBlockHeight: 1816201,
56+
DaytonaBlockHeight: 3238921,
5657
},
5758
Account: Account{
5859
InitBalanceMap: make(map[string]string),
@@ -132,6 +133,8 @@ type (
132133
CookBlockHeight uint64 `yaml:"cookHeight"`
133134
// DardanellesBlockHeight is the start height of 5s block internal
134135
DardanellesBlockHeight uint64 `yaml:"dardanellesHeight"`
136+
// DaytonaBlockHeight is the height to fix low gas for read native staking contract
137+
DaytonaBlockHeight uint64 `yaml:"daytonaBlockHeight"`
135138
}
136139
// Account contains the configs for account protocol
137140
Account struct {

config/heightupgrade.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2019 IoTeX
1+
// Copyright (c) 2020 IoTeX
22
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
33
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
44
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
@@ -17,19 +17,26 @@ const (
1717
Bering
1818
Cook
1919
Dardanelles
20+
Daytona
2021
)
2122

2223
type (
2324
// HeightName is codename for height upgrades
2425
HeightName int
2526

2627
// HeightUpgrade lists heights at which certain fixes take effect
28+
// prior to Dardanelles, each epoch consists of 360 sub-epochs
29+
// so height = 360k + 1
30+
// starting Dardanelles, each epoch consists of 720 sub-epochs
31+
// however, DardanellesHeight is set to 360(2k + 1) + 1 (instead of 720k + 1)
32+
// so height afterwards must be set to 360(2k + 1) + 1
2733
HeightUpgrade struct {
2834
pacificHeight uint64
2935
aleutianHeight uint64
3036
beringHeight uint64
3137
cookHeight uint64
3238
dardanellesHeight uint64
39+
daytonaHeight uint64
3340
}
3441
)
3542

@@ -41,6 +48,7 @@ func NewHeightUpgrade(cfg Config) HeightUpgrade {
4148
cfg.Genesis.BeringBlockHeight,
4249
cfg.Genesis.CookBlockHeight,
4350
cfg.Genesis.DardanellesBlockHeight,
51+
cfg.Genesis.DaytonaBlockHeight,
4452
}
4553
}
4654

@@ -58,6 +66,8 @@ func (hu *HeightUpgrade) IsPost(name HeightName, height uint64) bool {
5866
h = hu.cookHeight
5967
case Dardanelles:
6068
h = hu.dardanellesHeight
69+
case Daytona:
70+
h = hu.daytonaHeight
6171
default:
6272
log.Panic("invalid height name!")
6373
}
@@ -83,3 +93,6 @@ func (hu *HeightUpgrade) CookBlockHeight() uint64 { return hu.cookHeight }
8393

8494
// DardanellesBlockHeight returns the dardanelles height
8595
func (hu *HeightUpgrade) DardanellesBlockHeight() uint64 { return hu.dardanellesHeight }
96+
97+
// DaytonaBlockHeight returns the daytona height
98+
func (hu *HeightUpgrade) DaytonaBlockHeight() uint64 { return hu.daytonaHeight }

config/heightupgrade_test.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2019 IoTeX
1+
// Copyright (c) 2020 IoTeX
22
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
33
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
44
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
@@ -19,13 +19,17 @@ func TestNewHeightChange(t *testing.T) {
1919
require.Equal(1, Aleutian)
2020
require.Equal(2, Bering)
2121
require.Equal(3, Cook)
22+
require.Equal(4, Dardanelles)
23+
require.Equal(5, Daytona)
2224
cfg := Default
2325
cfg.Genesis.PacificBlockHeight = uint64(432001)
2426
hu := NewHeightUpgrade(cfg)
25-
require.Equal(uint64(432001), hu.pacificHeight)
26-
require.Equal(uint64(864001), hu.aleutianHeight)
27-
require.Equal(uint64(1512001), hu.beringHeight)
28-
require.Equal(uint64(1641601), hu.cookHeight)
27+
require.Equal(uint64(432001), hu.PacificBlockHeight())
28+
require.Equal(uint64(864001), hu.AleutianBlockHeight())
29+
require.Equal(uint64(1512001), hu.BeringBlockHeight())
30+
require.Equal(uint64(1641601), hu.CookBlockHeight())
31+
require.Equal(uint64(1816201), hu.DardanellesBlockHeight())
32+
require.Equal(uint64(3238921), hu.DaytonaBlockHeight())
2933

3034
require.True(hu.IsPre(Pacific, uint64(432000)))
3135
require.True(hu.IsPost(Pacific, uint64(432001)))
@@ -35,4 +39,8 @@ func TestNewHeightChange(t *testing.T) {
3539
require.True(hu.IsPost(Bering, uint64(1512001)))
3640
require.True(hu.IsPre(Cook, uint64(1641600)))
3741
require.True(hu.IsPost(Cook, uint64(1641601)))
42+
require.True(hu.IsPre(Dardanelles, uint64(1816200)))
43+
require.True(hu.IsPost(Dardanelles, uint64(1816201)))
44+
require.True(hu.IsPre(Daytona, uint64(3238920)))
45+
require.True(hu.IsPost(Daytona, uint64(3238921)))
3846
}

e2etest/staking_test.go

Lines changed: 190 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)