github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/poll/staking_command.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package poll 7 8 import ( 9 "context" 10 11 "github.com/iotexproject/go-pkgs/hash" 12 "github.com/iotexproject/iotex-address/address" 13 "github.com/pkg/errors" 14 15 "github.com/iotexproject/iotex-core/action" 16 "github.com/iotexproject/iotex-core/action/protocol" 17 "github.com/iotexproject/iotex-core/state" 18 ) 19 20 type stakingCommand struct { 21 addr address.Address 22 stakingV1 Protocol 23 stakingV2 Protocol 24 } 25 26 // NewStakingCommand creates a staking command center to manage staking committee and new native staking 27 func NewStakingCommand(stkV1 Protocol, stkV2 Protocol) (Protocol, error) { 28 if stkV1 == nil && stkV2 == nil { 29 return nil, errors.New("empty staking protocol") 30 } 31 32 h := hash.Hash160b([]byte(_protocolID)) 33 addr, err := address.FromBytes(h[:]) 34 if err != nil { 35 return nil, err 36 } 37 38 return &stakingCommand{ 39 addr: addr, 40 stakingV1: stkV1, 41 stakingV2: stkV2, 42 }, nil 43 } 44 45 func (sc *stakingCommand) CreateGenesisStates(ctx context.Context, sm protocol.StateManager) error { 46 // if v1 exists, bootstrap from v1 only 47 if sc.stakingV1 != nil { 48 return sc.stakingV1.CreateGenesisStates(ctx, sm) 49 } 50 return sc.stakingV2.CreateGenesisStates(ctx, sm) 51 } 52 53 func (sc *stakingCommand) Start(ctx context.Context, sr protocol.StateReader) (interface{}, error) { 54 if sc.stakingV1 != nil { 55 if starter, ok := sc.stakingV1.(protocol.Starter); ok { 56 if _, err := starter.Start(ctx, sr); err != nil { 57 return nil, err 58 } 59 } 60 } 61 62 if sc.stakingV2 != nil { 63 if starter, ok := sc.stakingV2.(protocol.Starter); ok { 64 return starter.Start(ctx, sr) 65 } 66 } 67 return nil, nil 68 } 69 70 func (sc *stakingCommand) CreatePreStates(ctx context.Context, sm protocol.StateManager) error { 71 if sc.useV2(ctx, sm) { 72 if p, ok := sc.stakingV2.(protocol.PreStatesCreator); ok { 73 return p.CreatePreStates(ctx, sm) 74 } 75 } 76 if p, ok := sc.stakingV1.(protocol.PreStatesCreator); ok { 77 return p.CreatePreStates(ctx, sm) 78 } 79 return nil 80 } 81 82 func (sc *stakingCommand) CreatePostSystemActions(ctx context.Context, sr protocol.StateReader) ([]action.Envelope, error) { 83 // no height here, v1 v2 has the same createPostSystemActions method, so directly use common one 84 return createPostSystemActions(ctx, sr, sc) 85 } 86 87 func (sc *stakingCommand) Handle(ctx context.Context, act action.Action, sm protocol.StateManager) (*action.Receipt, error) { 88 if sc.useV2(ctx, sm) { 89 return sc.stakingV2.Handle(ctx, act, sm) 90 } 91 return sc.stakingV1.Handle(ctx, act, sm) 92 } 93 94 func (sc *stakingCommand) Validate(ctx context.Context, act action.Action, sr protocol.StateReader) error { 95 // no height here, v1 v2 has the same validate method, so directly use common one 96 return validate(ctx, sr, sc, act) 97 } 98 99 func (sc *stakingCommand) CalculateCandidatesByHeight(ctx context.Context, sr protocol.StateReader, height uint64) (state.CandidateList, error) { 100 if sc.useV2ByHeight(ctx, height) { 101 return sc.stakingV2.CalculateCandidatesByHeight(ctx, sr, height) 102 } 103 return sc.stakingV1.CalculateCandidatesByHeight(ctx, sr, height) 104 } 105 106 func (sc *stakingCommand) CalculateUnproductiveDelegates( 107 ctx context.Context, 108 sr protocol.StateReader, 109 ) ([]string, error) { 110 if sc.useV2(ctx, sr) && protocol.MustGetFeatureCtx(ctx).FixUnproductiveDelegates { 111 return sc.stakingV2.CalculateUnproductiveDelegates(ctx, sr) 112 } 113 return sc.stakingV1.CalculateUnproductiveDelegates(ctx, sr) 114 } 115 116 // Delegates returns exact number of delegates of current epoch 117 func (sc *stakingCommand) Delegates(ctx context.Context, sr protocol.StateReader) (state.CandidateList, error) { 118 if sc.useV2(ctx, sr) { 119 return sc.stakingV2.Delegates(ctx, sr) 120 } 121 return sc.stakingV1.Delegates(ctx, sr) 122 } 123 124 // NextDelegates returns exact number of delegates of next epoch 125 func (sc *stakingCommand) NextDelegates(ctx context.Context, sr protocol.StateReader) (state.CandidateList, error) { 126 if sc.useV2(ctx, sr) { 127 return sc.stakingV2.NextDelegates(ctx, sr) 128 } 129 return sc.stakingV1.NextDelegates(ctx, sr) 130 } 131 132 // Candidates returns candidate list from state factory of current epoch 133 func (sc *stakingCommand) Candidates(ctx context.Context, sr protocol.StateReader) (state.CandidateList, error) { 134 if sc.useV2(ctx, sr) { 135 return sc.stakingV2.Candidates(ctx, sr) 136 } 137 return sc.stakingV1.Candidates(ctx, sr) 138 } 139 140 // NextCandidates returns candidate list from state factory of next epoch 141 func (sc *stakingCommand) NextCandidates(ctx context.Context, sr protocol.StateReader) (state.CandidateList, error) { 142 if sc.useV2(ctx, sr) { 143 return sc.stakingV2.NextCandidates(ctx, sr) 144 } 145 return sc.stakingV1.NextCandidates(ctx, sr) 146 } 147 148 func (sc *stakingCommand) ReadState(ctx context.Context, sr protocol.StateReader, method []byte, args ...[]byte) ([]byte, uint64, error) { 149 if sc.useV2(ctx, sr) { 150 res, height, err := sc.stakingV2.ReadState(ctx, sr, method, args...) 151 if err != nil && sc.stakingV1 != nil { 152 // check if reading from v1 only method 153 return sc.stakingV1.ReadState(ctx, sr, method, args...) 154 } 155 return res, height, nil 156 } 157 return sc.stakingV1.ReadState(ctx, sr, method, args...) 158 } 159 160 // Register registers the protocol with a unique ID 161 func (sc *stakingCommand) Register(r *protocol.Registry) error { 162 return r.Register(_protocolID, sc) 163 } 164 165 // ForceRegister registers the protocol with a unique ID and force replacing the previous protocol if it exists 166 func (sc *stakingCommand) ForceRegister(r *protocol.Registry) error { 167 return r.ForceRegister(_protocolID, sc) 168 } 169 170 func (sc *stakingCommand) Name() string { 171 return _protocolID 172 } 173 174 func (sc *stakingCommand) useV2(ctx context.Context, sr protocol.StateReader) bool { 175 height, err := sr.Height() 176 if err != nil { 177 panic("failed to return out height from state reader") 178 } 179 return sc.useV2ByHeight(ctx, height) 180 } 181 182 func (sc *stakingCommand) useV2ByHeight(ctx context.Context, height uint64) bool { 183 featureCtx := protocol.MustGetFeatureWithHeightCtx(ctx) 184 if sc.stakingV1 == nil || featureCtx.UseV2Staking(height) { 185 return true 186 } 187 return false 188 }