Fantom-foundation/go-lachesis

View on GitHub
gossip/poi.go

Summary

Maintainability
A
35 mins
Test Coverage
package gossip

import (
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"

    "github.com/Fantom-foundation/go-lachesis/evmcore"
    "github.com/Fantom-foundation/go-lachesis/inter"
    "github.com/Fantom-foundation/go-lachesis/inter/idx"
    "github.com/Fantom-foundation/go-lachesis/lachesis"
)

const (
    maxPoiDelegations = 1
)

// PoiPeriod calculate POI period from int64 unix time
func PoiPeriod(t inter.Timestamp, config *lachesis.EconomyConfig) uint64 {
    return uint64(t) / uint64(config.PoiPeriodDuration)
}

// UpdateAddressPOI calculate and save POI for user
func (s *Service) UpdateAddressPOI(address common.Address, senderTotalFee *big.Int, poiPeriod uint64) {
    /*if senderTotalFee.Sign() == 0 {
        s.store.SetAddressPOI(address, common.Big0)
        return // avoid division by 0
    }
    poi := new(big.Int).Mul(senderTotalFee, lachesis.PercentUnit)
    poi.Div(poi, s.store.GetPoiFee(poiPeriod)) // rebase user's PoI as <= 1.0 ratio
    s.store.SetAddressPOI(address, poi)*/
}

// updateUsersPOI calculates the Proof Of Importance weights for users
func (s *Service) updateUsersPOI(block *inter.Block, evmBlock *evmcore.EvmBlock, receipts types.Receipts, totalFee *big.Int, sealEpoch bool) {
    // User POI calculations
    poiPeriod := PoiPeriod(block.Time, &s.config.Net.Economy)
    s.app.AddPoiFee(poiPeriod, totalFee)

    for i, tx := range evmBlock.Transactions {
        txFee := new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())

        signer := types.NewEIP155Signer(s.config.Net.EvmChainConfig().ChainID)
        sender, err := signer.Sender(tx)
        if err != nil {
            s.Log.Crit("Failed to get sender from transaction", "err", err)
        }

        senderLastTxTime := s.app.GetAddressLastTxTime(sender)
        prevUserPoiPeriod := PoiPeriod(senderLastTxTime, &s.config.Net.Economy)
        senderTotalFee := s.app.GetAddressFee(sender, prevUserPoiPeriod)

        delegations := s.app.GetSfcDelegationsByAddr(sender, maxPoiDelegations)
        for _, it := range delegations {
            staker := s.app.GetSfcStaker(it.ID.StakerID)
            if staker != nil {
                prevWeightedTxFee := s.app.GetWeightedDelegationsFee(it.ID.StakerID)

                weightedTxFee := new(big.Int).Mul(txFee, it.Delegation.Amount)
                weightedTxFee.Div(weightedTxFee, staker.CalcTotalStake())

                weightedTxFee.Add(weightedTxFee, prevWeightedTxFee)
                s.app.SetWeightedDelegationsFee(it.ID.StakerID, weightedTxFee)
            }
        }

        if prevUserPoiPeriod != poiPeriod {
            s.UpdateAddressPOI(sender, senderTotalFee, prevUserPoiPeriod)
            senderTotalFee = big.NewInt(0)
        }

        s.app.SetAddressLastTxTime(sender, block.Time)
        senderTotalFee.Add(senderTotalFee, txFee)
        s.app.SetAddressFee(sender, poiPeriod, senderTotalFee)
    }

}

// UpdateStakerPOI calculate and save POI for staker
func (s *Service) UpdateStakerPOI(stakerID idx.StakerID, stakerAddress common.Address, poiPeriod uint64) {
    staker := s.app.GetSfcStaker(stakerID)

    vFee := s.app.GetAddressFee(stakerAddress, poiPeriod)
    weightedDFee := s.app.GetWeightedDelegationsFee(stakerID)
    if vFee.Sign() == 0 && weightedDFee.Sign() == 0 {
        s.app.SetStakerPOI(stakerID, common.Big0)
        return // optimization
    }

    weightedVFee := new(big.Int).Mul(vFee, staker.StakeAmount)
    weightedVFee.Div(weightedVFee, staker.CalcTotalStake())

    weightedFee := new(big.Int).Add(weightedDFee, weightedVFee)

    if weightedFee.Sign() == 0 {
        s.app.SetStakerPOI(stakerID, common.Big0)
        return // avoid division by 0
    }
    poi := weightedFee // no need to rebase validator's PoI as <= 1.0 ratio
    /*poi := new(big.Int).Mul(weightedFee, lachesis.PercentUnit)
    poi.Div(poi, s.store.GetPoiFee(poiPeriod))*/
    s.app.SetStakerPOI(stakerID, poi)
}

// updateStakersPOI calculates the Proof Of Importance weights for stakers
func (s *Service) updateStakersPOI(block *inter.Block, sealEpoch bool) {
    // Stakers POI calculations
    poiPeriod := PoiPeriod(block.Time, &s.config.Net.Economy)
    prevBlockPoiPeriod := PoiPeriod(s.store.GetBlock(block.Index-1).Time, &s.config.Net.Economy)

    if poiPeriod != prevBlockPoiPeriod {
        for _, it := range s.GetActiveSfcStakers() {
            s.UpdateStakerPOI(it.StakerID, it.Staker.Address, prevBlockPoiPeriod)
        }
        // clear StakersDelegationsFee counters
        s.app.DelAllWeightedDelegationsFee()
    }
}