mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
Merge pull request #68 from dinhln89/reward
Reward to candidate's owner and coin holders
This commit is contained in:
commit
02a1bd2b53
7 changed files with 201 additions and 822 deletions
|
|
@ -360,7 +360,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Fail to connect RPC: %v", err)
|
utils.Fatalf("Fail to connect RPC: %v", err)
|
||||||
}
|
}
|
||||||
addr := common.HexToAddress(common.Validator)
|
addr := common.HexToAddress(common.MasternodeVotingSMC)
|
||||||
validator, err := validatorContract.NewTomoValidator(addr, client)
|
validator, err := validatorContract.NewTomoValidator(addr, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Fail to get validator smc: %v", err)
|
utils.Fatalf("Fail to get validator smc: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HashLength = 32
|
HashLength = 32
|
||||||
AddressLength = 20
|
AddressLength = 20
|
||||||
BlockSigners = "0x0000000000000000000000000000000000000089"
|
BlockSigners = "0x0000000000000000000000000000000000000089"
|
||||||
Validator = "0x0000000000000000000000000000000000000088"
|
MasternodeVotingSMC = "0x0000000000000000000000000000000000000088"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/contracts/blocksigner/contract"
|
"github.com/ethereum/go-ethereum/contracts/blocksigner/contract"
|
||||||
|
contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -14,7 +16,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HexSignMethod = "2fb1b25f"
|
HexSignMethod = "2fb1b25f"
|
||||||
|
RewardMasterPercent = 30
|
||||||
|
RewardVoterPercent = 60
|
||||||
|
RewardFoundationPercent = 10
|
||||||
|
FoudationWalletAddr = "0x0000000000000000000000000000000000000068"
|
||||||
)
|
)
|
||||||
|
|
||||||
type rewardLog struct {
|
type rewardLog struct {
|
||||||
|
|
@ -117,7 +123,7 @@ func GetRewardForCheckpoint(blockSignerAddr common.Address, number uint64, rChec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate reward for signers.
|
// Calculate reward for signers.
|
||||||
func CalculateReward(chainReward *big.Int, signers map[common.Address]*rewardLog, totalSigner uint64) (map[common.Address]*big.Int, error) {
|
func CalculateRewardForSigner(chainReward *big.Int, signers map[common.Address]*rewardLog, totalSigner uint64) (map[common.Address]*big.Int, error) {
|
||||||
resultSigners := make(map[common.Address]*big.Int)
|
resultSigners := make(map[common.Address]*big.Int)
|
||||||
// Add reward for signers.
|
// Add reward for signers.
|
||||||
for signer, rLog := range signers {
|
for signer, rLog := range signers {
|
||||||
|
|
@ -138,3 +144,80 @@ func CalculateReward(chainReward *big.Int, signers map[common.Address]*rewardLog
|
||||||
|
|
||||||
return resultSigners, nil
|
return resultSigners, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get candidate owner by address.
|
||||||
|
func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, signerAddr common.Address) common.Address {
|
||||||
|
owner := signerAddr
|
||||||
|
opts := new(bind.CallOpts)
|
||||||
|
owner, err := validator.GetCandidateOwner(opts, signerAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Fail get candidate owner", "error", err)
|
||||||
|
return owner
|
||||||
|
}
|
||||||
|
|
||||||
|
return owner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate reward for holders.
|
||||||
|
func CalculateRewardForHolders(validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) error {
|
||||||
|
rewards, err := GetRewardBalancesRate(signer, calcReward, validator)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(rewards) > 0 {
|
||||||
|
for holder, reward := range rewards {
|
||||||
|
state.AddBalance(holder, reward)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get reward balance rates for master node, founder and holders.
|
||||||
|
func GetRewardBalancesRate(masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) {
|
||||||
|
owner := GetCandidatesOwnerBySigner(validator, masterAddr)
|
||||||
|
balances := make(map[common.Address]*big.Int)
|
||||||
|
rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(RewardMasterPercent))
|
||||||
|
rewardMaster = new(big.Int).Div(rewardMaster, new(big.Int).SetInt64(100))
|
||||||
|
balances[owner] = rewardMaster
|
||||||
|
// Get voters for masternode.
|
||||||
|
opts := new(bind.CallOpts)
|
||||||
|
voters, err := validator.GetVoters(opts, masterAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Fail to get voters", "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(voters) > 0 {
|
||||||
|
totalVoterReward := new(big.Int).Mul(totalReward, new(big.Int).SetUint64(RewardVoterPercent))
|
||||||
|
totalVoterReward = new(big.Int).Div(totalVoterReward, new(big.Int).SetUint64(100))
|
||||||
|
totalCap := new(big.Int)
|
||||||
|
// Get voters capacities.
|
||||||
|
voterCaps := make(map[common.Address]*big.Int)
|
||||||
|
for _, voteAddr := range voters {
|
||||||
|
voterCap, err := validator.GetVoterCap(opts, masterAddr, voteAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Fail to get vote capacity", "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
totalCap.Add(totalCap, voterCap)
|
||||||
|
voterCaps[voteAddr] = voterCap
|
||||||
|
}
|
||||||
|
for addr, voteCap := range voterCaps {
|
||||||
|
balances[addr] = new(big.Int).Mul(totalVoterReward, voteCap)
|
||||||
|
balances[addr] = new(big.Int).Div(balances[addr], totalCap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foudationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(RewardFoundationPercent))
|
||||||
|
foudationReward = new(big.Int).Div(foudationReward, new(big.Int).SetInt64(100))
|
||||||
|
balances[common.HexToAddress(FoudationWalletAddr)] = foudationReward
|
||||||
|
|
||||||
|
jsonHolders, err := json.Marshal(balances)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Fail to parse json holders", "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Info("Holders reward", "holders", string(jsonHolders), "master node", masterAddr.String())
|
||||||
|
|
||||||
|
return balances, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ func TestSendTxSign(t *testing.T) {
|
||||||
signers[common.HexToAddress("0x12f588d7d03bb269b382b842fc15d874e8c055a7")] = &rewardLog{5, new(big.Int).SetUint64(0)}
|
signers[common.HexToAddress("0x12f588d7d03bb269b382b842fc15d874e8c055a7")] = &rewardLog{5, new(big.Int).SetUint64(0)}
|
||||||
signers[common.HexToAddress("0x1f9e122c0921a4504fc116d967baf7a7bf2604ef")] = &rewardLog{6, new(big.Int).SetUint64(0)}
|
signers[common.HexToAddress("0x1f9e122c0921a4504fc116d967baf7a7bf2604ef")] = &rewardLog{6, new(big.Int).SetUint64(0)}
|
||||||
signers[common.HexToAddress("0xea489e4e673c25ff0614617ebe88efd853efe00c")] = &rewardLog{6, new(big.Int).SetUint64(0)}
|
signers[common.HexToAddress("0xea489e4e673c25ff0614617ebe88efd853efe00c")] = &rewardLog{6, new(big.Int).SetUint64(0)}
|
||||||
rewardSigners, err := CalculateReward(chainReward, signers, totalSigner)
|
rewardSigners, err := CalculateRewardForSigner(chainReward, signers, totalSigner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Fail to calculate reward for signers: %v", err)
|
t.Errorf("Fail to calculate reward for signers: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,25 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
|
"github.com/ethereum/go-ethereum/contracts"
|
||||||
|
"github.com/ethereum/go-ethereum/contracts/validator/contract"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
|
||||||
|
acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
acc4Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey)
|
||||||
|
acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey)
|
||||||
|
acc3Addr = crypto.PubkeyToAddress(acc3Key.PublicKey)
|
||||||
|
acc4Addr = crypto.PubkeyToAddress(acc4Key.PublicKey)
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidator(t *testing.T) {
|
func TestValidator(t *testing.T) {
|
||||||
|
|
@ -37,3 +49,84 @@ func TestValidator(t *testing.T) {
|
||||||
}
|
}
|
||||||
contractBackend.Commit()
|
contractBackend.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRewardBalance(t *testing.T) {
|
||||||
|
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{
|
||||||
|
acc1Addr: {Balance: new(big.Int).SetUint64(10000000)},
|
||||||
|
acc2Addr: {Balance: new(big.Int).SetUint64(10000000)},
|
||||||
|
acc4Addr: {Balance: new(big.Int).SetUint64(10000000)},
|
||||||
|
})
|
||||||
|
acc1Opts := bind.NewKeyedTransactor(acc1Key)
|
||||||
|
acc2Opts := bind.NewKeyedTransactor(acc2Key)
|
||||||
|
accounts := []*bind.TransactOpts{acc1Opts, acc2Opts}
|
||||||
|
transactOpts := bind.NewKeyedTransactor(acc1Key)
|
||||||
|
|
||||||
|
validatorAddr, _, baseValidator, err := contract.DeployTomoValidator(transactOpts, contractBackend, big.NewInt(50000), big.NewInt(99), big.NewInt(100))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("can't deploy root registry: %v", err)
|
||||||
|
}
|
||||||
|
contractBackend.Commit()
|
||||||
|
|
||||||
|
// Propose master node acc3Addr.
|
||||||
|
opts := bind.NewKeyedTransactor(acc4Key)
|
||||||
|
opts.Value = new(big.Int).SetUint64(50000)
|
||||||
|
acc4Validator, _ := NewValidator(opts, validatorAddr, contractBackend)
|
||||||
|
acc4Validator.Propose(acc3Addr, "http://")
|
||||||
|
contractBackend.Commit()
|
||||||
|
|
||||||
|
totalVote := 0
|
||||||
|
type logCap struct {
|
||||||
|
Addr string
|
||||||
|
Balance int
|
||||||
|
}
|
||||||
|
logCaps := make(map[int]*logCap)
|
||||||
|
for i := 0; i <= 10; i++ {
|
||||||
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
|
randIndex := rand.Intn(len(accounts))
|
||||||
|
randCap := rand.Intn(10) * 1000
|
||||||
|
if randCap <= 0 {
|
||||||
|
randCap = 1000
|
||||||
|
}
|
||||||
|
totalVote += randCap
|
||||||
|
accounts[randIndex].Value = new(big.Int).SetInt64(int64(randCap))
|
||||||
|
validator, err := NewValidator(accounts[randIndex], validatorAddr, contractBackend)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("can't get current validator: %v", err)
|
||||||
|
}
|
||||||
|
validator.Vote(acc3Addr)
|
||||||
|
contractBackend.Commit()
|
||||||
|
logCaps[i] = &logCap{accounts[randIndex].From.String(), randCap}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalReward := new(big.Int).SetInt64(15 * 1000)
|
||||||
|
rewards, err := contracts.GetRewardBalancesRate(acc3Addr, totalReward, baseValidator)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("Fail to get reward balances rate.", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
afterReward := new(big.Int)
|
||||||
|
for _, value := range rewards {
|
||||||
|
afterReward = new(big.Int).Add(afterReward, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalReward.Int64()+1 < afterReward.Int64() || totalReward.Int64()-1 > afterReward.Int64() {
|
||||||
|
callOpts := new(bind.CallOpts)
|
||||||
|
voters, err := baseValidator.GetVoters(callOpts, acc3Addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Can not get voters in validator contract.", err)
|
||||||
|
}
|
||||||
|
for addr, capacity := range logCaps {
|
||||||
|
t.Errorf("from %v - %v", addr, capacity)
|
||||||
|
}
|
||||||
|
for _, voter := range voters {
|
||||||
|
voteCap, _ := baseValidator.GetVoterCap(callOpts, acc3Addr, voter)
|
||||||
|
t.Errorf("vote %v - %v", voter.String(), voteCap)
|
||||||
|
}
|
||||||
|
for addr, value := range rewards {
|
||||||
|
t.Errorf("reaward %v - %v", addr.String(), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Errorf("reward total %v - %v", totalReward, afterReward)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
808
devnet.json
808
devnet.json
File diff suppressed because one or more lines are too long
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/contracts"
|
"github.com/ethereum/go-ethereum/contracts"
|
||||||
|
"github.com/ethereum/go-ethereum/contracts/validator/contract"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
|
@ -195,7 +196,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
importedHook := func(block *types.Block) {
|
importedHook := func(block *types.Block) {
|
||||||
snap, err := c.GetSnapshot(eth.blockchain, block.Header())
|
snap, err := c.GetSnapshot(eth.blockchain, block.Header())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Fail to get snapshot for sign tx validator.")
|
log.Error("Fail to get snapshot for sign tx validator.", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, authorized := snap.Signers[eth.etherbase]; authorized {
|
if _, authorized := snap.Signers[eth.etherbase]; authorized {
|
||||||
|
|
@ -227,14 +228,24 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Fail to get signers for reward checkpoint", "error", err)
|
log.Error("Fail to get signers for reward checkpoint", "error", err)
|
||||||
}
|
}
|
||||||
rewardSigners, err := contracts.CalculateReward(chainReward, signers, *totalSigner)
|
rewardSigners, err := contracts.CalculateRewardForSigner(chainReward, signers, *totalSigner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Fail to calculate reward for signers", "error", err)
|
log.Error("Fail to calculate reward for signers", "error", err)
|
||||||
}
|
}
|
||||||
// Add reward for signers.
|
//// Get validator.
|
||||||
|
validator, err := contract.NewTomoValidator(common.HexToAddress(common.MasternodeVotingSMC), client)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Fail get instance of Tomo Validator", "error", err)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Add reward for coin holders.
|
||||||
if len(signers) > 0 {
|
if len(signers) > 0 {
|
||||||
for signer, calcReward := range rewardSigners {
|
for signer, calcReward := range rewardSigners {
|
||||||
state.AddBalance(signer, calcReward)
|
err := contracts.CalculateRewardForHolders(validator, state, signer, calcReward)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Fail to calculate reward for holders.", "error", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue