mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-20 13:44:31 +00:00
238 lines
No EOL
7.9 KiB
Go
238 lines
No EOL
7.9 KiB
Go
package contracts
|
|
|
|
import (
|
|
"encoding/json"
|
|
"github.com/ethereum/go-ethereum/accounts"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/consensus"
|
|
"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/state"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
"math/big"
|
|
)
|
|
|
|
const (
|
|
HexSignMethod = "e341eaa4"
|
|
RewardMasterPercent = 30
|
|
RewardVoterPercent = 60
|
|
RewardFoundationPercent = 10
|
|
FoudationWalletAddr = "0x0000000000000000000000000000000000000068"
|
|
)
|
|
|
|
type rewardLog struct {
|
|
Sign uint64 `json:"sign"`
|
|
Reward *big.Int `json:"reward"`
|
|
}
|
|
|
|
// Send tx sign for block number to smart contract blockSigner.
|
|
func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, manager *accounts.Manager, block *types.Block) error {
|
|
if chainConfig.Clique != nil {
|
|
// Find active account.
|
|
account := accounts.Account{}
|
|
var wallet accounts.Wallet
|
|
if wallets := manager.Wallets(); len(wallets) > 0 {
|
|
wallet = wallets[0]
|
|
if accts := wallets[0].Accounts(); len(accts) > 0 {
|
|
account = accts[0]
|
|
}
|
|
}
|
|
|
|
// Create and send tx to smart contract for sign validate block.
|
|
nonce := pool.State().GetNonce(account.Address)
|
|
tx := CreateTxSign(block.Number(), block.Hash(), nonce, common.HexToAddress(common.BlockSigners))
|
|
txSigned, err := wallet.SignTx(account, tx, chainConfig.ChainId)
|
|
if err != nil {
|
|
log.Error("Fail to create tx sign", "error", err)
|
|
return err
|
|
}
|
|
|
|
// Add tx signed to local tx pool.
|
|
pool.AddLocal(txSigned)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Create tx sign.
|
|
func CreateTxSign(blockNumber *big.Int, blockHash common.Hash, nonce uint64, blockSigner common.Address) *types.Transaction {
|
|
data := common.Hex2Bytes(HexSignMethod)
|
|
inputData := append(data, common.LeftPadBytes(blockNumber.Bytes(), 32)...)
|
|
inputData = append(inputData, common.LeftPadBytes(blockHash.Bytes(), 32)...)
|
|
tx := types.NewTransaction(nonce, blockSigner, big.NewInt(0), 200000, big.NewInt(0), inputData)
|
|
|
|
return tx
|
|
}
|
|
|
|
// Get signers signed for blockNumber from blockSigner contract.
|
|
func GetSignersFromContract(addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) {
|
|
blockSigner, err := contract.NewBlockSigner(addrBlockSigner, client)
|
|
if err != nil {
|
|
log.Error("Fail get instance of blockSigner", "error", err)
|
|
return nil, err
|
|
}
|
|
opts := new(bind.CallOpts)
|
|
addrs, err := blockSigner.GetSigners(opts, blockHash)
|
|
if err != nil {
|
|
log.Error("Fail get block signers", "error", err)
|
|
return nil, err
|
|
}
|
|
|
|
return addrs, nil
|
|
}
|
|
|
|
// Calculate reward for reward checkpoint.
|
|
func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common.Address, number uint64, rCheckpoint uint64, client bind.ContractBackend, totalSigner *uint64) (map[common.Address]*rewardLog, error) {
|
|
// Not reward for singer of genesis block and only calculate reward at checkpoint block.
|
|
startBlockNumber := number - (rCheckpoint * 2) + 1
|
|
endBlockNumber := startBlockNumber + rCheckpoint - 1
|
|
signers := make(map[common.Address]*rewardLog)
|
|
|
|
for i := startBlockNumber; i <= endBlockNumber; i++ {
|
|
block := chain.GetHeaderByNumber(i)
|
|
addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash())
|
|
if err != nil {
|
|
log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i)
|
|
return nil, err
|
|
}
|
|
// Filter duplicate address.
|
|
if len(addrs) > 0 {
|
|
addrSigners := make(map[common.Address]bool)
|
|
for _, addr := range addrs {
|
|
if _, ok := addrSigners[addr]; !ok {
|
|
addrSigners[addr] = true
|
|
}
|
|
}
|
|
for addr := range addrSigners {
|
|
_, exist := signers[addr]
|
|
if exist {
|
|
signers[addr].Sign++
|
|
} else {
|
|
signers[addr] = &rewardLog{1, new(big.Int)}
|
|
}
|
|
*totalSigner++
|
|
}
|
|
}
|
|
}
|
|
|
|
log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
|
|
|
|
return signers, nil
|
|
}
|
|
|
|
// Calculate reward for signers.
|
|
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)
|
|
// Add reward for signers.
|
|
if totalSigner > 0 {
|
|
for signer, rLog := range signers {
|
|
// Add reward for signer.
|
|
calcReward := new(big.Int)
|
|
calcReward.Div(chainReward, new(big.Int).SetUint64(totalSigner))
|
|
calcReward.Mul(calcReward, new(big.Int).SetUint64(rLog.Sign))
|
|
rLog.Reward = calcReward
|
|
|
|
resultSigners[signer] = calcReward
|
|
}
|
|
}
|
|
jsonSigners, err := json.Marshal(signers)
|
|
if err != nil {
|
|
log.Error("Fail to parse json signers", "error", err)
|
|
return nil, err
|
|
}
|
|
log.Info("Signers data", "signers", string(jsonSigners), "totalSigner", totalSigner, "totalReward", chainReward)
|
|
|
|
return resultSigners, nil
|
|
}
|
|
|
|
// Get candidate owner by address.
|
|
func GetCandidatesOwnerBySigner(validator *contractValidator.XDCValidator, 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.XDCValidator, 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.XDCValidator) (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
|
|
}
|
|
if totalCap.Cmp(new(big.Int).SetInt64(0)) > 0 {
|
|
for addr, voteCap := range voterCaps {
|
|
// Only valid voter has cap > 0.
|
|
if voteCap.Cmp(new(big.Int).SetInt64(0)) > 0 {
|
|
rcap := new(big.Int).Mul(totalVoterReward, voteCap)
|
|
rcap = new(big.Int).Div(rcap, totalCap)
|
|
if balances[addr] != nil {
|
|
balances[addr].Add(balances[addr], rcap)
|
|
} else {
|
|
balances[addr] = rcap
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
} |