|
|
|
@ -1,11 +1,12 @@ |
|
|
|
|
package apr |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"github.com/harmony-one/harmony/core/types" |
|
|
|
|
"github.com/harmony-one/harmony/shard" |
|
|
|
|
"math/big" |
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
|
"github.com/harmony-one/harmony/block" |
|
|
|
|
"github.com/harmony-one/harmony/core/state" |
|
|
|
|
"github.com/harmony-one/harmony/internal/params" |
|
|
|
|
"github.com/harmony-one/harmony/internal/utils" |
|
|
|
|
"github.com/harmony-one/harmony/numeric" |
|
|
|
@ -15,6 +16,7 @@ import ( |
|
|
|
|
|
|
|
|
|
// Reader ..
|
|
|
|
|
type Reader interface { |
|
|
|
|
GetHeaderByNumber(number uint64) *block.Header |
|
|
|
|
Config() *params.ChainConfig |
|
|
|
|
GetHeaderByHash(hash common.Hash) *block.Header |
|
|
|
|
// GetHeader retrieves a block header from the database by hash and number.
|
|
|
|
@ -27,7 +29,7 @@ type Reader interface { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
secondsInYear = int64(31_557_600) |
|
|
|
|
secondsInYear = int64(31557600) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
@ -35,14 +37,13 @@ var ( |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func expectedRewardPerYear( |
|
|
|
|
oneEpochAgo, twoEpochAgo *block.Header, |
|
|
|
|
oneSnapshotAgo, twoSnapshotAgo *staking.ValidatorWrapper, |
|
|
|
|
blocksPerEpoch uint64, |
|
|
|
|
now, oneEpochAgo *block.Header, |
|
|
|
|
curValidator, snapshotLastEpoch *staking.ValidatorWrapper, |
|
|
|
|
) (*big.Int, error) { |
|
|
|
|
oneTAgo, twoTAgo := oneEpochAgo.Time(), twoEpochAgo.Time() |
|
|
|
|
timeNow, oneTAgo := now.Time(), oneEpochAgo.Time() |
|
|
|
|
diffTime, diffReward := |
|
|
|
|
new(big.Int).Sub(twoTAgo, oneTAgo), |
|
|
|
|
new(big.Int).Sub(twoSnapshotAgo.BlockReward, oneSnapshotAgo.BlockReward) |
|
|
|
|
new(big.Int).Sub(timeNow, oneTAgo), |
|
|
|
|
new(big.Int).Sub(curValidator.BlockReward, snapshotLastEpoch.BlockReward) |
|
|
|
|
|
|
|
|
|
// impossibility but keep sane
|
|
|
|
|
if diffTime.Sign() == -1 { |
|
|
|
@ -55,152 +56,81 @@ func expectedRewardPerYear( |
|
|
|
|
// TODO some more sanity checks of some sort?
|
|
|
|
|
expectedValue := new(big.Int).Div(diffReward, diffTime) |
|
|
|
|
expectedPerYear := new(big.Int).Mul(expectedValue, oneYear) |
|
|
|
|
utils.Logger().Info(). |
|
|
|
|
utils.Logger().Info().Interface("now", curValidator).Interface("before", snapshotLastEpoch). |
|
|
|
|
Uint64("diff-reward", diffReward.Uint64()). |
|
|
|
|
Uint64("diff-time", diffTime.Uint64()). |
|
|
|
|
Uint64("expected-value", expectedValue.Uint64()). |
|
|
|
|
Uint64("expected-per-year", expectedPerYear.Uint64()). |
|
|
|
|
Interface("expected-value", expectedValue). |
|
|
|
|
Interface("expected-per-year", expectedPerYear). |
|
|
|
|
Msg("expected reward per year computed") |
|
|
|
|
return expectedPerYear, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func pastTwoEpochHeaders( |
|
|
|
|
var ( |
|
|
|
|
zero = numeric.ZeroDec() |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// ComputeForValidator ..
|
|
|
|
|
func ComputeForValidator( |
|
|
|
|
bc Reader, |
|
|
|
|
) (*block.Header, *block.Header, error) { |
|
|
|
|
current := bc.CurrentHeader() |
|
|
|
|
epochNow := current.Epoch() |
|
|
|
|
oneEpochAgo, twoEpochAgo := |
|
|
|
|
new(big.Int).Sub(epochNow, common.Big1), |
|
|
|
|
new(big.Int).Sub(epochNow, common.Big2) |
|
|
|
|
|
|
|
|
|
bottomOut := new(big.Int).Add( |
|
|
|
|
bc.Config().StakingEpoch, |
|
|
|
|
common.Big3, |
|
|
|
|
) |
|
|
|
|
block *types.Block, |
|
|
|
|
validatorNow *staking.ValidatorWrapper, |
|
|
|
|
) (*numeric.Dec, error) { |
|
|
|
|
oneEpochAgo, zero := |
|
|
|
|
new(big.Int).Sub(block.Epoch(), common.Big1), |
|
|
|
|
numeric.ZeroDec() |
|
|
|
|
|
|
|
|
|
var oneAgoHeader, twoAgoHeader **block.Header |
|
|
|
|
utils.Logger().Info(). |
|
|
|
|
Uint64("now", block.Epoch().Uint64()). |
|
|
|
|
Uint64("one-epoch-ago", oneEpochAgo.Uint64()). |
|
|
|
|
Msg("apr - begin compute for validator ") |
|
|
|
|
|
|
|
|
|
for e1, e2 := false, false; ; { |
|
|
|
|
current = bc.GetHeader(current.ParentHash(), current.Number().Uint64()-1) |
|
|
|
|
oneSnapshotAgo, err := bc.ReadValidatorSnapshotAtEpoch( |
|
|
|
|
oneEpochAgo, |
|
|
|
|
validatorNow.Address, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if current == nil { |
|
|
|
|
return nil, nil, errors.New("could not go up parent") |
|
|
|
|
if err != nil { |
|
|
|
|
return &zero, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if current.Epoch().Cmp(bottomOut) == 0 { |
|
|
|
|
if twoAgoHeader == nil || oneAgoHeader == nil { |
|
|
|
|
return nil, nil, errors.New( |
|
|
|
|
"could not find headers for apr computation", |
|
|
|
|
blockNumAtOneEpochAgo := shard.Schedule.EpochLastBlock(oneEpochAgo.Uint64()) |
|
|
|
|
|
|
|
|
|
headerOneEpochAgo := bc.GetHeaderByNumber(blockNumAtOneEpochAgo) |
|
|
|
|
if block.Header() == nil || headerOneEpochAgo == nil || err != nil { |
|
|
|
|
utils.Logger().Debug(). |
|
|
|
|
Msgf("apr compute headers epochs ago %+v %+v %+v", |
|
|
|
|
oneEpochAgo, |
|
|
|
|
blockNumAtOneEpochAgo, |
|
|
|
|
headerOneEpochAgo, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
return &zero, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch { |
|
|
|
|
// haven't found either epoch yet
|
|
|
|
|
case !e1 && !e2: |
|
|
|
|
if current.Epoch().Cmp(oneEpochAgo) == 0 { |
|
|
|
|
e1 = true |
|
|
|
|
oneAgoHeader = ¤t |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
case e1 && !e2: |
|
|
|
|
if current.Epoch().Cmp(twoEpochAgo) == 0 { |
|
|
|
|
e2 = true |
|
|
|
|
twoAgoHeader = ¤t |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
utils.Logger().Info(). |
|
|
|
|
RawJSON("current-epoch-header", []byte(bc.CurrentHeader().String())). |
|
|
|
|
RawJSON("one-epoch-ago-header", []byte(headerOneEpochAgo.String())). |
|
|
|
|
Msg("headers used for apr computation") |
|
|
|
|
|
|
|
|
|
return *oneAgoHeader, *twoAgoHeader, nil |
|
|
|
|
} |
|
|
|
|
estimatedRewardPerYear, err := expectedRewardPerYear( |
|
|
|
|
block.Header(), headerOneEpochAgo, |
|
|
|
|
validatorNow, oneSnapshotAgo, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
zero = numeric.ZeroDec() |
|
|
|
|
) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ComputeForValidator ..
|
|
|
|
|
func ComputeForValidator( |
|
|
|
|
bc Reader, |
|
|
|
|
now *big.Int, |
|
|
|
|
state *state.DB, |
|
|
|
|
validatorNow *staking.ValidatorWrapper, |
|
|
|
|
blocksPerEpoch uint64, |
|
|
|
|
) (*numeric.Dec, error) { |
|
|
|
|
if estimatedRewardPerYear.Cmp(common.Big0) == 0 { |
|
|
|
|
return &zero, nil |
|
|
|
|
// twoEpochAgo, oneEpochAgo, zero :=
|
|
|
|
|
// new(big.Int).Sub(now, common.Big2),
|
|
|
|
|
// new(big.Int).Sub(now, common.Big1),
|
|
|
|
|
// numeric.ZeroDec()
|
|
|
|
|
|
|
|
|
|
// utils.Logger().Info().
|
|
|
|
|
// Uint64("now", now.Uint64()).
|
|
|
|
|
// Uint64("two-epoch-ago", twoEpochAgo.Uint64()).
|
|
|
|
|
// Uint64("one-epoch-ago", oneEpochAgo.Uint64()).
|
|
|
|
|
// Msg("apr - begin compute for validator ")
|
|
|
|
|
|
|
|
|
|
// twoSnapshotAgo, err := bc.ReadValidatorSnapshotAtEpoch(
|
|
|
|
|
// twoEpochAgo,
|
|
|
|
|
// validatorNow.Address,
|
|
|
|
|
// )
|
|
|
|
|
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// return &zero, nil
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// oneSnapshotAgo, err := bc.ReadValidatorSnapshotAtEpoch(
|
|
|
|
|
// oneEpochAgo,
|
|
|
|
|
// validatorNow.Address,
|
|
|
|
|
// )
|
|
|
|
|
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// return &zero, nil
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// blockNumAtTwoEpochAgo, blockNumAtOneEpochAgo :=
|
|
|
|
|
// shard.Schedule.EpochLastBlock(twoEpochAgo.Uint64()),
|
|
|
|
|
// shard.Schedule.EpochLastBlock(oneEpochAgo.Uint64())
|
|
|
|
|
|
|
|
|
|
// headerOneEpochAgo, headerTwoEpochAgo, err := pastTwoEpochHeaders(bc)
|
|
|
|
|
|
|
|
|
|
// // TODO Figure out why this is happening
|
|
|
|
|
// if headerOneEpochAgo == nil || headerTwoEpochAgo == nil || err != nil {
|
|
|
|
|
// utils.Logger().Debug().
|
|
|
|
|
// Msgf("apr compute headers epochs ago %+v %+v %+v %+v %+v %+v",
|
|
|
|
|
// twoEpochAgo, oneEpochAgo,
|
|
|
|
|
// blockNumAtTwoEpochAgo, blockNumAtOneEpochAgo,
|
|
|
|
|
// headerOneEpochAgo, headerTwoEpochAgo,
|
|
|
|
|
// )
|
|
|
|
|
// return &zero, nil
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// utils.Logger().Info().
|
|
|
|
|
// RawJSON("current-epoch-header", []byte(bc.CurrentHeader().String())).
|
|
|
|
|
// RawJSON("one-epoch-ago-header", []byte(headerOneEpochAgo.String())).
|
|
|
|
|
// RawJSON("two-epoch-ago-header", []byte(headerTwoEpochAgo.String())).
|
|
|
|
|
// Msg("headers used for apr computation")
|
|
|
|
|
|
|
|
|
|
// estimatedRewardPerYear, err := expectedRewardPerYear(
|
|
|
|
|
// headerOneEpochAgo, headerTwoEpochAgo,
|
|
|
|
|
// oneSnapshotAgo, twoSnapshotAgo,
|
|
|
|
|
// blocksPerEpoch,
|
|
|
|
|
// )
|
|
|
|
|
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// return nil, err
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if estimatedRewardPerYear.Cmp(common.Big0) == 0 {
|
|
|
|
|
// return &zero, nil
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// total := numeric.NewDecFromBigInt(validatorNow.TotalDelegation())
|
|
|
|
|
// if total.IsZero() {
|
|
|
|
|
// return nil, errors.New("zero total delegation will cause div by zero")
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// result := numeric.NewDecFromBigInt(estimatedRewardPerYear).Quo(
|
|
|
|
|
// total,
|
|
|
|
|
// )
|
|
|
|
|
// return &result, nil
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
total := numeric.NewDecFromBigInt(validatorNow.TotalDelegation()) |
|
|
|
|
if total.IsZero() { |
|
|
|
|
return nil, errors.New("zero total delegation will cause div by zero") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
result := numeric.NewDecFromBigInt(estimatedRewardPerYear).Quo( |
|
|
|
|
total, |
|
|
|
|
) |
|
|
|
|
return &result, nil |
|
|
|
|
} |
|
|
|
|