Skip to content

Commit fb80b0e

Browse files
authored
Make native staking contract be loadable from genesis (#1542)
1 parent 723f268 commit fb80b0e

File tree

9 files changed

+114
-20
lines changed

9 files changed

+114
-20
lines changed

action/const.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var (
1212
// ErrActPool indicates the error of actpool
1313
ErrActPool = errors.New("invalid actpool")
1414
// ErrHitGasLimit is the error when hit gas limit
15-
ErrHitGasLimit = errors.New("Hit Gas Limit")
15+
ErrHitGasLimit = errors.New("Hit gas limit")
1616
// ErrInsufficientBalanceForGas is the error that the balance in executor account is lower than gas
1717
ErrInsufficientBalanceForGas = errors.New("Insufficient balance for gas")
1818
// ErrOutOfGas is the error when running out of gas

action/protocol/execution/evm/evm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func NewParams(
8080

8181
gasLimit := execution.GasLimit()
8282
// Reset gas limit to the system wide action gas limit cap if it's greater than it
83-
if hu.IsPre(config.Aleutian, raCtx.BlockHeight) && gasLimit > preAleutianActionGasLimit {
83+
if raCtx.BlockHeight > 0 && hu.IsPre(config.Aleutian, raCtx.BlockHeight) && gasLimit > preAleutianActionGasLimit {
8484
gasLimit = preAleutianActionGasLimit
8585
}
8686

action/protocol/poll/nativestaking.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ type (
6060
)
6161

6262
// NewNativeStaking creates a NativeStaking instance
63-
func NewNativeStaking(cm protocol.ChainManager, getTipBlockTime GetTipBlockTime, staking string) (*NativeStaking, error) {
63+
func NewNativeStaking(cm protocol.ChainManager, getTipBlockTime GetTipBlockTime) (*NativeStaking, error) {
6464
abi, err := abi.JSON(strings.NewReader(NsAbi))
6565
if err != nil {
6666
return nil, err
@@ -71,10 +71,11 @@ func NewNativeStaking(cm protocol.ChainManager, getTipBlockTime GetTipBlockTime,
7171
if getTipBlockTime == nil {
7272
return nil, errors.New("failed to create native staking: empty getBlockTime")
7373
}
74-
if _, err := address.FromString(staking); err != nil {
75-
return nil, errors.Errorf("invalid staking contract %s", staking)
76-
}
77-
return &NativeStaking{cm, getTipBlockTime, staking, abi}, nil
74+
return &NativeStaking{
75+
cm: cm,
76+
getTipBlockTime: getTipBlockTime,
77+
abi: abi,
78+
}, nil
7879
}
7980

8081
// Votes returns the votes on height
@@ -160,6 +161,15 @@ func (ns *NativeStaking) readBuckets(prevIndx, limit *big.Int) ([]*types.Bucket,
160161
return buckets, nil
161162
}
162163

164+
// SetContract sets the contract address
165+
func (ns *NativeStaking) SetContract(contract string) {
166+
if _, err := address.FromString(contract); err != nil {
167+
zap.S().Panicf("Invalid staking contract %s", contract)
168+
}
169+
ns.contract = contract
170+
zap.S().Infof("Set native staking contract address = %s", contract)
171+
}
172+
163173
func (vt *VoteTally) tally(buckets []*types.Bucket, now time.Time) error {
164174
for i := range buckets {
165175
v := buckets[i]

action/protocol/poll/nativestaking_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,10 @@ func TestStaking(t *testing.T) {
3939

4040
mcm := &protocol.MockChainManager{}
4141
getTime := func() (time.Time, error) { return time.Now(), nil }
42-
ns, err := NewNativeStaking(nil, getTime, "")
42+
ns, err := NewNativeStaking(mcm, nil)
4343
require.Error(err)
44-
ns, err = NewNativeStaking(mcm, nil, "")
45-
require.Error(err)
46-
ns, err = NewNativeStaking(mcm, getTime, "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqd39yn7")
47-
require.Error(err)
48-
ns, err = NewNativeStaking(mcm, getTime, "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqd39ym7")
44+
ns, err = NewNativeStaking(mcm, getTime)
45+
ns.SetContract("io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqd39ym7")
4946
require.NoError(err)
5047

5148
pygg := &pygg{}

action/protocol/poll/protocol.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ type Protocol interface {
6969
DelegatesByHeight(uint64) (state.CandidateList, error)
7070
// ReadState read the state on blockchain via protocol
7171
ReadState(context.Context, protocol.StateManager, []byte, ...[]byte) ([]byte, error)
72+
// SetContract sets the native staking contract address
73+
SetNativeStakingContract(string)
7274
}
7375

7476
type lifeLongDelegatesProtocol struct {
@@ -142,6 +144,10 @@ func (p *lifeLongDelegatesProtocol) ReadState(
142144
}
143145
}
144146

147+
func (p *lifeLongDelegatesProtocol) SetNativeStakingContract(contract string) {
148+
zap.S().Panic("Not implemented")
149+
}
150+
145151
func (p *lifeLongDelegatesProtocol) readBlockProducers() ([]byte, error) {
146152
return p.delegates.Serialize()
147153
}
@@ -337,6 +343,10 @@ func (p *governanceChainCommitteeProtocol) ReadState(
337343
}
338344
}
339345

346+
func (p *governanceChainCommitteeProtocol) SetNativeStakingContract(contract string) {
347+
zap.S().Panic("Not implemented")
348+
}
349+
340350
func (p *governanceChainCommitteeProtocol) readDelegatesByEpoch(epochNum uint64) (state.CandidateList, error) {
341351
epochHeight := p.getEpochHeight(epochNum)
342352
return p.cm.CandidatesByHeight(epochHeight)

action/protocol/poll/staking_committee.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ func NewStakingCommittee(
4949
getTipBlockTime GetTipBlockTime,
5050
getEpochHeight GetEpochHeight,
5151
getEpochNum GetEpochNum,
52-
staking string,
52+
nativeStakingContractAddress string,
53+
nativeStakingContractCode string,
5354
rp *rolldpos.Protocol,
5455
scoreThreshold *big.Int,
5556
) (Protocol, error) {
@@ -60,11 +61,14 @@ func NewStakingCommittee(
6061
return nil, errors.New("failed to create native staking: empty getEpochNum")
6162
}
6263
var ns *NativeStaking
63-
if staking != "" {
64+
if nativeStakingContractAddress != "" || nativeStakingContractCode != "" {
6465
var err error
65-
if ns, err = NewNativeStaking(cm, getTipBlockTime, staking); err != nil {
66+
if ns, err = NewNativeStaking(cm, getTipBlockTime); err != nil {
6667
return nil, errors.New("failed to create native staking")
6768
}
69+
if nativeStakingContractAddress != "" {
70+
ns.SetContract(nativeStakingContractAddress)
71+
}
6872
}
6973
return &stakingCommittee{
7074
hu: hu,
@@ -125,6 +129,11 @@ func (sc *stakingCommittee) ReadState(ctx context.Context, sm protocol.StateMana
125129
return sc.governanceStaking.ReadState(ctx, sm, method, args...)
126130
}
127131

132+
// SetNativeStakingContract sets the address of native staking contract
133+
func (sc *stakingCommittee) SetNativeStakingContract(contract string) {
134+
sc.nativeStaking.SetContract(contract)
135+
}
136+
128137
func (sc *stakingCommittee) mergeDelegates(list state.CandidateList, votes *VoteTally, ts time.Time) state.CandidateList {
129138
// as of now, native staking does not have register contract, only voting/staking contract
130139
// it is assumed that all votes done on native staking target for delegates registered on Ethereum

blockchain/blockchain.go

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,19 @@ import (
1515
"sync/atomic"
1616
"time"
1717

18+
"github.com/ethereum/go-ethereum/common"
19+
"github.com/ethereum/go-ethereum/common/hexutil"
20+
ecrypto "github.com/ethereum/go-ethereum/crypto"
1821
"github.com/facebookgo/clock"
19-
"github.com/iotexproject/go-pkgs/bloom"
20-
"github.com/iotexproject/go-pkgs/hash"
21-
"github.com/iotexproject/iotex-address/address"
2222
"github.com/pkg/errors"
2323
"github.com/prometheus/client_golang/prometheus"
2424
"go.uber.org/zap"
2525
"google.golang.org/grpc/codes"
2626
"google.golang.org/grpc/status"
2727

28+
"github.com/iotexproject/go-pkgs/bloom"
29+
"github.com/iotexproject/go-pkgs/hash"
30+
"github.com/iotexproject/iotex-address/address"
2831
"github.com/iotexproject/iotex-core/action"
2932
"github.com/iotexproject/iotex-core/action/protocol"
3033
"github.com/iotexproject/iotex-core/action/protocol/account"
@@ -45,6 +48,7 @@ import (
4548
"github.com/iotexproject/iotex-core/pkg/util/fileutil"
4649
"github.com/iotexproject/iotex-core/state"
4750
"github.com/iotexproject/iotex-core/state/factory"
51+
"github.com/iotexproject/iotex-proto/golang/iotextypes"
4852
)
4953

5054
var (
@@ -944,6 +948,7 @@ func (bc *blockchain) startExistingBlockchain() error {
944948
if err != nil {
945949
return errors.Wrap(err, "failed to get factory's height")
946950
}
951+
bc.loadingNativeStakingContract()
947952
log.L().Info("Restarting blockchain.",
948953
zap.Uint64("chainHeight",
949954
bc.tipHeight),
@@ -1330,6 +1335,11 @@ func (bc *blockchain) createGenesisStates(ws factory.WorkingSet) error {
13301335
return err
13311336
}
13321337
}
1338+
if bc.config.Genesis.NativeStakingContractCode != "" {
1339+
if err := bc.createNativeStakingContract(ctx, ws); err != nil {
1340+
return err
1341+
}
1342+
}
13331343
return bc.createRewardingGenesisStates(ctx, ws)
13341344
}
13351345

@@ -1388,6 +1398,61 @@ func (bc *blockchain) createPollGenesisStates(ctx context.Context, ws factory.Wo
13881398
return nil
13891399
}
13901400

1401+
func (bc *blockchain) createNativeStakingContract(ctx context.Context, ws factory.WorkingSet) error {
1402+
raCtx := protocol.MustGetRunActionsCtx(ctx)
1403+
raCtx.Producer, _ = address.FromString(address.ZeroAddress)
1404+
raCtx.Caller, _ = address.FromString(address.ZeroAddress)
1405+
raCtx.GasLimit = bc.config.Genesis.BlockGasLimit
1406+
bytes, err := hexutil.Decode(bc.config.Genesis.NativeStakingContractCode)
1407+
if err != nil {
1408+
return err
1409+
}
1410+
hu := config.NewHeightUpgrade(bc.config)
1411+
execution, err := action.NewExecution(
1412+
"",
1413+
0,
1414+
big.NewInt(0),
1415+
bc.config.Genesis.BlockGasLimit,
1416+
big.NewInt(0),
1417+
bytes,
1418+
)
1419+
if err != nil {
1420+
return err
1421+
}
1422+
_, receipt, err := evm.ExecuteContract(protocol.WithRunActionsCtx(ctx, raCtx), ws, execution, bc, hu)
1423+
if err != nil {
1424+
return err
1425+
}
1426+
if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) {
1427+
return errors.Errorf("error when deploying native staking contract, status=%d", receipt.Status)
1428+
}
1429+
p, ok := bc.registry.Find(poll.ProtocolID)
1430+
if ok {
1431+
pp, ok := p.(poll.Protocol)
1432+
if ok {
1433+
pp.SetNativeStakingContract(receipt.ContractAddress)
1434+
log.L().Info("Deployed native staking contract", zap.String("address", receipt.ContractAddress))
1435+
}
1436+
}
1437+
return nil
1438+
}
1439+
1440+
func (bc *blockchain) loadingNativeStakingContract() {
1441+
if bc.config.Genesis.NativeStakingContractAddress == "" && bc.config.Genesis.NativeStakingContractCode != "" {
1442+
p, ok := bc.registry.Find(poll.ProtocolID)
1443+
if ok {
1444+
pp, ok := p.(poll.Protocol)
1445+
if ok {
1446+
caller, _ := address.FromString(address.ZeroAddress)
1447+
ethAddr := ecrypto.CreateAddress(common.BytesToAddress(caller.Bytes()), 0)
1448+
iotxAddr, _ := address.FromBytes(ethAddr.Bytes())
1449+
pp.SetNativeStakingContract(iotxAddr.String())
1450+
log.L().Info("Loaded native staking contract", zap.String("address", iotxAddr.String()))
1451+
}
1452+
}
1453+
}
1454+
}
1455+
13911456
func (bc *blockchain) updateAleutianEpochRewardAmount(ctx context.Context, ws factory.WorkingSet) error {
13921457
p, ok := bc.registry.Find(rewarding.ProtocolID)
13931458
if !ok {

blockchain/genesis/genesis.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,10 @@ type (
142142
RegisterContractAddress string `yaml:"registerContractAddress"`
143143
// StakingContractAddress is the address of staking contract
144144
StakingContractAddress string `yaml:"stakingContractAddress"`
145-
// NativeStakingContractAddress is the address of staking contract on mainnet
145+
// NativeStakingContractAddress is the address of native staking contract
146146
NativeStakingContractAddress string `yaml:"nativeStakingContractAddress"`
147+
// NativeStakingContractCode is the code of native staking contract
148+
NativeStakingContractCode string `yaml:"nativeStakingContractCode"`
147149
// VoteThreshold is the vote threshold amount in decimal string format
148150
VoteThreshold string `yaml:"voteThreshold"`
149151
// ScoreThreshold is the score threshold amount in decimal string format

server/itx/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ func registerDefaultProtocols(cs *chainservice.ChainService, cfg config.Config)
319319
rolldposProtocol.GetEpochHeight,
320320
rolldposProtocol.GetEpochNum,
321321
cfg.Genesis.NativeStakingContractAddress,
322+
cfg.Genesis.NativeStakingContractCode,
322323
rolldposProtocol,
323324
scoreThreshold,
324325
); err != nil {

0 commit comments

Comments
 (0)