mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
175 lines
No EOL
5.4 KiB
Go
175 lines
No EOL
5.4 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/contracts/blocksigner/contract"
|
|
contract2 "github.com/ethereum/go-ethereum/contracts/validator/contract"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
"math/big"
|
|
)
|
|
|
|
const (
|
|
HexSignMethod = "2fb1b25f"
|
|
)
|
|
|
|
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(), 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, nonce uint64, blockSigner common.Address) *types.Transaction {
|
|
blockHex := common.LeftPadBytes(blockNumber.Bytes(), 32)
|
|
data := common.Hex2Bytes(HexSignMethod)
|
|
inputData := append(data, blockHex...)
|
|
tx := types.NewTransaction(nonce, blockSigner, big.NewInt(0), 100000, big.NewInt(0), inputData)
|
|
|
|
return tx
|
|
}
|
|
|
|
// Get signers signed for blockNumber from blockSigner contract.
|
|
func GetSignersFromContract(addrBlockSigner common.Address, client bind.ContractBackend, blockNumber uint64) ([]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, new(big.Int).SetUint64(blockNumber))
|
|
if err != nil {
|
|
log.Error("Fail get block signers", "error", err)
|
|
return nil, err
|
|
}
|
|
|
|
return addrs, nil
|
|
}
|
|
|
|
// Calculate reward for reward checkpoint.
|
|
func GetRewardForCheckpoint(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++ {
|
|
addrs, err := GetSignersFromContract(blockSignerAddr, client, i)
|
|
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++
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get Owner for signers.
|
|
owners := make(map[common.Address]*rewardLog)
|
|
if len(signers) > 0 {
|
|
for addr, log := range signers {
|
|
owner, err := GetCandidatesOwnerByAddress(client, addr)
|
|
if err != nil {
|
|
owner = addr
|
|
}
|
|
if _, ok := owners[owner]; ok {
|
|
owners[owner].Sign = owners[owner].Sign + log.Sign
|
|
} else {
|
|
owners[owner] = log
|
|
}
|
|
}
|
|
}
|
|
|
|
log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
|
|
|
|
return owners, nil
|
|
}
|
|
|
|
// Calculate reward for signers.
|
|
func CalculateReward(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.
|
|
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 GetCandidatesOwnerByAddress(client bind.ContractBackend, addr common.Address) (common.Address, error) {
|
|
owner := common.Address{}
|
|
validator, err := contract2.NewXDCValidator(common.HexToAddress(common.XDCValidator), client)
|
|
if err != nil {
|
|
log.Error("Fail get instance of XDC Validator", "error", err)
|
|
return owner, err
|
|
}
|
|
opts := new(bind.CallOpts)
|
|
owner, err = validator.GetCandidateOwner(opts, addr)
|
|
if err != nil {
|
|
log.Error("Fail get candidate owner", "error", err)
|
|
return owner, err
|
|
}
|
|
|
|
return owner, nil
|
|
} |