github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/rewarding/admin.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 rewarding 7 8 import ( 9 "context" 10 "math/big" 11 12 "github.com/pkg/errors" 13 "google.golang.org/protobuf/proto" 14 15 "github.com/iotexproject/iotex-address/address" 16 "github.com/iotexproject/iotex-core/action/protocol" 17 "github.com/iotexproject/iotex-core/action/protocol/rewarding/rewardingpb" 18 "github.com/iotexproject/iotex-core/blockchain/genesis" 19 ) 20 21 // admin stores the admin data of the rewarding protocol 22 type admin struct { 23 blockReward *big.Int 24 epochReward *big.Int 25 numDelegatesForEpochReward uint64 26 foundationBonus *big.Int 27 numDelegatesForFoundationBonus uint64 28 foundationBonusLastEpoch uint64 29 productivityThreshold uint64 30 } 31 32 // Serialize serializes admin state into bytes 33 func (a admin) Serialize() ([]byte, error) { 34 gen := rewardingpb.Admin{ 35 BlockReward: a.blockReward.String(), 36 EpochReward: a.epochReward.String(), 37 NumDelegatesForEpochReward: a.numDelegatesForEpochReward, 38 FoundationBonus: a.foundationBonus.String(), 39 NumDelegatesForFoundationBonus: a.numDelegatesForFoundationBonus, 40 FoundationBonusLastEpoch: a.foundationBonusLastEpoch, 41 ProductivityThreshold: a.productivityThreshold, 42 } 43 return proto.Marshal(&gen) 44 } 45 46 // Deserialize deserializes bytes into admin state 47 func (a *admin) Deserialize(data []byte) error { 48 gen := rewardingpb.Admin{} 49 if err := proto.Unmarshal(data, &gen); err != nil { 50 return err 51 } 52 blockReward, ok := new(big.Int).SetString(gen.BlockReward, 10) 53 if !ok { 54 return errors.New("failed to set block reward") 55 } 56 epochReward, ok := new(big.Int).SetString(gen.EpochReward, 10) 57 if !ok { 58 return errors.New("failed to set epoch reward") 59 } 60 foundationBonus, ok := new(big.Int).SetString(gen.FoundationBonus, 10) 61 if !ok { 62 return errors.New("failed to set bootstrap bonus") 63 } 64 a.blockReward = blockReward 65 a.epochReward = epochReward 66 a.numDelegatesForEpochReward = gen.NumDelegatesForEpochReward 67 a.foundationBonus = foundationBonus 68 a.numDelegatesForFoundationBonus = gen.NumDelegatesForFoundationBonus 69 a.foundationBonusLastEpoch = gen.FoundationBonusLastEpoch 70 a.productivityThreshold = gen.ProductivityThreshold 71 return nil 72 } 73 74 func (a *admin) grantFoundationBonus(epoch uint64) bool { 75 return epoch <= a.foundationBonusLastEpoch 76 } 77 78 // exempt stores the addresses that exempt from epoch reward 79 type exempt struct { 80 addrs []address.Address 81 } 82 83 // Serialize serializes exempt state into bytes 84 func (e *exempt) Serialize() ([]byte, error) { 85 epb := rewardingpb.Exempt{} 86 for _, addr := range e.addrs { 87 epb.Addrs = append(epb.Addrs, addr.Bytes()) 88 } 89 return proto.Marshal(&epb) 90 } 91 92 // Deserialize deserializes bytes into exempt state 93 func (e *exempt) Deserialize(data []byte) error { 94 epb := rewardingpb.Exempt{} 95 if err := proto.Unmarshal(data, &epb); err != nil { 96 return err 97 } 98 e.addrs = nil 99 for _, addrBytes := range epb.Addrs { 100 addr, err := address.FromBytes(addrBytes) 101 if err != nil { 102 return err 103 } 104 e.addrs = append(e.addrs, addr) 105 } 106 return nil 107 } 108 109 // CreateGenesisStates initializes the rewarding protocol by setting the original admin, block and epoch reward 110 func (p *Protocol) CreateGenesisStates( 111 ctx context.Context, 112 sm protocol.StateManager, 113 ) error { 114 blkCtx := protocol.MustGetBlockCtx(ctx) 115 g := genesis.MustExtractGenesisContext(ctx) 116 if err := p.assertZeroBlockHeight(blkCtx.BlockHeight); err != nil { 117 return err 118 } 119 120 blockReward := g.BlockReward() 121 if err := p.assertAmount(blockReward); err != nil { 122 return err 123 } 124 125 epochReward := g.EpochReward() 126 if err := p.assertAmount(epochReward); err != nil { 127 return err 128 } 129 130 if err := p.putState( 131 ctx, 132 sm, 133 _adminKey, 134 &admin{ 135 blockReward: blockReward, 136 epochReward: epochReward, 137 numDelegatesForEpochReward: g.NumDelegatesForEpochReward, 138 foundationBonus: g.FoundationBonus(), 139 numDelegatesForFoundationBonus: g.NumDelegatesForFoundationBonus, 140 foundationBonusLastEpoch: g.FoundationBonusLastEpoch, 141 productivityThreshold: g.ProductivityThreshold, 142 }, 143 ); err != nil { 144 return err 145 } 146 147 initBalance := g.InitBalance() 148 if err := p.putState( 149 ctx, 150 sm, 151 _fundKey, 152 &fund{ 153 totalBalance: initBalance, 154 unclaimedBalance: initBalance, 155 }, 156 ); err != nil { 157 return err 158 } 159 return p.putState( 160 ctx, 161 sm, 162 _exemptKey, 163 &exempt{ 164 addrs: g.ExemptAddrsFromEpochReward(), 165 }, 166 ) 167 } 168 169 // BlockReward returns the block reward amount 170 func (p *Protocol) BlockReward( 171 ctx context.Context, 172 sm protocol.StateReader, 173 ) (*big.Int, error) { 174 a := admin{} 175 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 176 return nil, err 177 } 178 return a.blockReward, nil 179 } 180 181 // EpochReward returns the epoch reward amount 182 func (p *Protocol) EpochReward( 183 ctx context.Context, 184 sm protocol.StateReader, 185 ) (*big.Int, error) { 186 a := admin{} 187 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 188 return nil, err 189 } 190 return a.epochReward, nil 191 } 192 193 // NumDelegatesForEpochReward returns the number of candidates sharing an epoch reward 194 func (p *Protocol) NumDelegatesForEpochReward( 195 ctx context.Context, 196 sm protocol.StateManager, 197 ) (uint64, error) { 198 a := admin{} 199 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 200 return 0, err 201 } 202 return a.numDelegatesForEpochReward, nil 203 } 204 205 // FoundationBonus returns the foundation bonus amount 206 func (p *Protocol) FoundationBonus(ctx context.Context, sm protocol.StateReader) (*big.Int, error) { 207 a := admin{} 208 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 209 return nil, err 210 } 211 return a.foundationBonus, nil 212 } 213 214 // FoundationBonusLastEpoch returns the last epoch when the foundation bonus will still be granted 215 func (p *Protocol) FoundationBonusLastEpoch(ctx context.Context, sm protocol.StateReader) (uint64, error) { 216 a := admin{} 217 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 218 return 0, err 219 } 220 return a.foundationBonusLastEpoch, nil 221 } 222 223 // NumDelegatesForFoundationBonus returns the number of delegates that will get foundation bonus 224 func (p *Protocol) NumDelegatesForFoundationBonus(ctx context.Context, sm protocol.StateReader) (uint64, error) { 225 a := admin{} 226 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 227 return 0, err 228 } 229 return a.numDelegatesForFoundationBonus, nil 230 } 231 232 // ProductivityThreshold returns the productivity threshold 233 func (p *Protocol) ProductivityThreshold(ctx context.Context, sm protocol.StateManager) (uint64, error) { 234 a := admin{} 235 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 236 return 0, err 237 } 238 return a.productivityThreshold, nil 239 } 240 241 // SetReward updates block or epoch reward amount 242 func (p *Protocol) SetReward( 243 ctx context.Context, 244 sm protocol.StateManager, 245 amount *big.Int, 246 blockLevel bool, 247 ) error { 248 if err := p.assertAmount(amount); err != nil { 249 return err 250 } 251 a := admin{} 252 if _, err := p.state(ctx, sm, _adminKey, &a); err != nil { 253 return err 254 } 255 if blockLevel { 256 a.blockReward = amount 257 } else { 258 a.epochReward = amount 259 } 260 return p.putState(ctx, sm, _adminKey, &a) 261 } 262 263 func (p *Protocol) assertAmount(amount *big.Int) error { 264 if amount.Cmp(big.NewInt(0)) >= 0 { 265 return nil 266 } 267 return errors.Errorf("amount %s shouldn't be negative", amount.String()) 268 } 269 270 func (p *Protocol) assertZeroBlockHeight(height uint64) error { 271 if height != 0 { 272 return errors.Errorf("current block height %d is not zero", height) 273 } 274 return nil 275 }