-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #124 from NodeFactoryIo/mmuftic/payout-script-impl…
…ementation Calculating reward distribution
- Loading branch information
Showing
16 changed files
with
522 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package payout | ||
|
||
import ( | ||
"github.com/NodeFactoryIo/vedran/internal/models" | ||
"math" | ||
"math/big" | ||
) | ||
|
||
const ( | ||
livelinessRewardPercentage = 0.1 | ||
requestsRewardPercentage = 0.9 | ||
) | ||
|
||
func CalculatePayoutDistributionByNode( | ||
payoutDetails map[string]models.NodeStatsDetails, | ||
totalReward float64, | ||
loadBalancerFeePercentage float64, | ||
) map[string]big.Int { | ||
var rewardPool = totalReward | ||
|
||
loadbalancerReward := rewardPool * loadBalancerFeePercentage | ||
rewardPool -= loadbalancerReward | ||
|
||
livelinessRewardPool := rewardPool * livelinessRewardPercentage | ||
requestsRewardPool := rewardPool * requestsRewardPercentage | ||
|
||
var totalNumberOfPings = float64(0) | ||
var totalNumberOfRequests = float64(0) | ||
for _, node := range payoutDetails { | ||
totalNumberOfPings += node.TotalPings | ||
totalNumberOfRequests += node.TotalRequests | ||
} | ||
|
||
totalDistributedLivelinessRewards := float64(0) | ||
totalDistributedRequestsRewards := float64(0) | ||
payoutAmountDistributionByNodes := make(map[string]big.Int, len(payoutDetails)) | ||
|
||
for nodeId, nodeStatsDetails := range payoutDetails { | ||
// liveliness rewards | ||
livelinessReward := float64(0) | ||
if totalNumberOfPings != 0 && nodeStatsDetails.TotalPings != 0 { | ||
nodeLivelinessRewardPercentage := nodeStatsDetails.TotalPings / totalNumberOfPings | ||
livelinessReward = livelinessRewardPool * nodeLivelinessRewardPercentage | ||
livelinessReward = math.Floor(livelinessReward) | ||
totalDistributedLivelinessRewards += livelinessReward | ||
} | ||
// requests rewards | ||
requestsReward := float64(0) | ||
if totalNumberOfRequests != 0 && nodeStatsDetails.TotalRequests != 0 { | ||
nodeRequestsRewardPercentage := nodeStatsDetails.TotalRequests / totalNumberOfRequests | ||
requestsReward = requestsRewardPool * nodeRequestsRewardPercentage | ||
requestsReward = math.Floor(requestsReward) | ||
totalDistributedRequestsRewards += requestsReward | ||
} | ||
|
||
totalNodeReward := livelinessReward + requestsReward | ||
totalNodeRewardAsInt, _ := big.NewFloat(totalNodeReward).Int(nil) | ||
payoutAmountDistributionByNodes[nodeId] = *totalNodeRewardAsInt | ||
} | ||
|
||
return payoutAmountDistributionByNodes | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package payout | ||
|
||
import ( | ||
"github.com/NodeFactoryIo/vedran/internal/models" | ||
"github.com/stretchr/testify/assert" | ||
"math/big" | ||
"testing" | ||
) | ||
|
||
func Test_CalculatePayoutDistributionByNode(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
payoutDetails map[string]models.NodeStatsDetails | ||
totalReward float64 | ||
loadBalancerFee float64 | ||
resultDistribution map[string]big.Int | ||
}{ | ||
{ // this test is set for 10/90 split between liveliness and requests | ||
name: "test distribution", | ||
payoutDetails: map[string]models.NodeStatsDetails{ | ||
"1": { | ||
TotalPings: 100, | ||
TotalRequests: 10, | ||
}, | ||
"2": { | ||
TotalPings: 100, | ||
TotalRequests: 5, | ||
}, | ||
"3": { | ||
TotalPings: 90, | ||
TotalRequests: 10, | ||
}, | ||
"4": { | ||
TotalPings: 90, | ||
TotalRequests: 5, | ||
}, | ||
"5": { | ||
TotalPings: 50, | ||
TotalRequests: 2, | ||
}, | ||
"6": { | ||
TotalPings: 40, | ||
TotalRequests: 0, | ||
}, | ||
}, | ||
totalReward: 100000000, | ||
loadBalancerFee: 0.1, | ||
resultDistribution: map[string]big.Int{ | ||
"1": *big.NewInt(27227393), // 27227393.617021276 // 100P 10R | ||
"2": *big.NewInt(14571143), // 14571143.617021276 // 100P 5R | ||
"3": *big.NewInt(27035904), // 27035904.255319147 // 90P 10R | ||
"4": *big.NewInt(14379654), // 14379654.25531915 // 90P 5R | ||
"5": *big.NewInt(6019946), // 6019946.808510638 // 50P 2R | ||
"6": *big.NewInt(765957), // 765957.4468085106 // 40P 0R | ||
}, | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
distributionByNode := CalculatePayoutDistributionByNode( | ||
test.payoutDetails, test.totalReward, test.loadBalancerFee, | ||
) | ||
assert.Equal(t, test.resultDistribution, distributionByNode) | ||
totalDistributed := big.NewInt(0) | ||
for _, amount := range distributionByNode { | ||
totalDistributed.Add(totalDistributed, &amount) | ||
} | ||
totalShoudBeDistributed := test.totalReward * (float64(1) - test.loadBalancerFee) | ||
|
||
totalShouldBeDistributedRounded, _ := big.NewFloat(totalShoudBeDistributed).Int(nil) | ||
delta := big.NewInt(0).Sub(totalShouldBeDistributedRounded, totalDistributed) | ||
assert.GreaterOrEqual(t, delta.Int64(), int64(0)) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package payout | ||
|
||
import ( | ||
"github.com/NodeFactoryIo/vedran/internal/models" | ||
"github.com/NodeFactoryIo/vedran/internal/repositories" | ||
"github.com/NodeFactoryIo/vedran/internal/stats" | ||
log "github.com/sirupsen/logrus" | ||
"time" | ||
) | ||
|
||
type NodePayoutDetails struct { | ||
Stats models.NodeStatsDetails `json:"stats"` | ||
PayoutAddress string `json:"payout_address"` | ||
} | ||
|
||
func GetStatsForPayout( | ||
repos repositories.Repos, | ||
intervalEnd time.Time, | ||
recordPayout bool, | ||
) (map[string]NodePayoutDetails, error) { | ||
|
||
statistics, err := stats.CalculateStatisticsFromLastPayout(repos, intervalEnd) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
payoutStatistics := make(map[string]NodePayoutDetails, len(statistics)) | ||
for nodeId, statsDetails := range statistics { | ||
node, _ := repos.NodeRepo.FindByID(nodeId) | ||
payoutStatistics[nodeId] = NodePayoutDetails{ | ||
Stats: statsDetails, | ||
PayoutAddress: node.PayoutAddress, | ||
} | ||
} | ||
|
||
if recordPayout { | ||
err = repos.PayoutRepo.Save(&models.Payout{ | ||
Timestamp: intervalEnd, | ||
PaymentDetails: statistics, | ||
}) | ||
if err != nil { | ||
log.Errorf("Unable to save payout information to database, because of: %v", err) | ||
return nil, err | ||
} | ||
} | ||
|
||
return payoutStatistics, nil | ||
} |
Oops, something went wrong.