mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
XIN-121 Reward hook (#57)
* v2 Hook Reward, need test * test reward * fix RewardHook due to modifying params config directly (#56) * more test * finish test Co-authored-by: Jerome <wjrjerome@gmail.com>
This commit is contained in:
parent
9b47146120
commit
89acbdd742
8 changed files with 352 additions and 24 deletions
|
|
@ -53,7 +53,7 @@ type XDPoS_v2 struct {
|
|||
highestTimeoutCert *utils.TimeoutCert
|
||||
highestCommitBlock *utils.BlockInfo
|
||||
|
||||
HookReward func(chain consensus.ChainReader, state *state.StateDB, parentState *state.StateDB, header *types.Header) (error, map[string]interface{})
|
||||
HookReward func(chain consensus.ChainReader, state *state.StateDB, parentState *state.StateDB, header *types.Header) (map[string]interface{}, error)
|
||||
HookPenalty func(chain consensus.ChainReader, number *big.Int, parentHash common.Hash, candidates []common.Address) ([]common.Address, error)
|
||||
}
|
||||
|
||||
|
|
@ -235,13 +235,14 @@ func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) er
|
|||
// rewards given, and returns the final block.
|
||||
func (x *XDPoS_v2) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, parentState *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
||||
// set block reward
|
||||
number := header.Number.Uint64()
|
||||
rCheckpoint := chain.Config().XDPoS.RewardCheckpoint
|
||||
|
||||
// _ = c.CacheData(header, txs, receipts)
|
||||
|
||||
if x.HookReward != nil && number%rCheckpoint == 0 {
|
||||
err, rewards := x.HookReward(chain, state, parentState, header)
|
||||
isEpochSwitch, _, err := x.IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
log.Error("[Finalize] IsEpochSwitch bug!", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
if x.HookReward != nil && isEpochSwitch {
|
||||
rewards, err := x.HookReward(chain, state, parentState, header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1385,20 +1386,30 @@ func (x *XDPoS_v2) GetMasternodesByHash(chain consensus.ChainReader, hash common
|
|||
return epochSwitchInfo.Masternodes
|
||||
}
|
||||
|
||||
// Given hash, get master node from the epoch switch block of the previous `limit` epoch
|
||||
func (x *XDPoS_v2) GetPreviousPenaltyByHash(chain consensus.ChainReader, hash common.Hash, limit int) []common.Address {
|
||||
// get epoch switch of the previous `limit` epoch
|
||||
func (x *XDPoS_v2) getPreviousEpochSwitchInfoByHash(chain consensus.ChainReader, hash common.Hash, limit int) (*utils.EpochSwitchInfo, error) {
|
||||
epochSwitchInfo, err := x.getEpochSwitchInfo(chain, nil, hash)
|
||||
if err != nil {
|
||||
log.Error("[GetMasternodes] Adaptor v2 getEpochSwitchInfo has error, potentially bug", "err", err)
|
||||
return []common.Address{}
|
||||
log.Error("[getPreviousEpochSwitchInfoByHash] Adaptor v2 getEpochSwitchInfo has error, potentially bug", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < limit; i++ {
|
||||
epochSwitchInfo, err = x.getEpochSwitchInfo(chain, nil, epochSwitchInfo.EpochSwitchParentBlockInfo.Hash)
|
||||
if err != nil {
|
||||
log.Error("[GetMasternodes] Adaptor v2 getEpochSwitchInfo has error, potentially bug", "err", err)
|
||||
return []common.Address{}
|
||||
log.Error("[getPreviousEpochSwitchInfoByHash] Adaptor v2 getEpochSwitchInfo has error, potentially bug", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return epochSwitchInfo, nil
|
||||
}
|
||||
|
||||
// Given hash, get master node from the epoch switch block of the previous `limit` epoch
|
||||
func (x *XDPoS_v2) GetPreviousPenaltyByHash(chain consensus.ChainReader, hash common.Hash, limit int) []common.Address {
|
||||
epochSwitchInfo, err := x.getPreviousEpochSwitchInfoByHash(chain, hash, limit)
|
||||
if err != nil {
|
||||
log.Error("[GetPreviousPenaltyByHash] Adaptor v2 getPreviousEpochSwitchInfoByHash has error, potentially bug", "err", err)
|
||||
return []common.Address{}
|
||||
}
|
||||
header := chain.GetHeaderByHash(epochSwitchInfo.EpochSwitchBlockInfo.Hash)
|
||||
return common.ExtractAddressFromBytes(header.Penalties)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ func TestHookPenaltyV2Comeback(t *testing.T) {
|
|||
assert.Equal(t, 4, len(penalty))
|
||||
header6285 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*7 - common.MergeSignRange)
|
||||
// forcely insert signing tx into cache, to cancel comeback. since no comeback, penalty is 3
|
||||
tx, err := signingTx(header6285, 0, signer, signFn)
|
||||
tx, err := signingTxWithSignerFn(header6285, 0, signer, signFn)
|
||||
assert.Nil(t, err)
|
||||
adaptor.CacheSigningTxs(header6285.Hash(), []*types.Transaction{tx})
|
||||
penalty, err = adaptor.EngineV2.HookPenalty(blockchain, big.NewInt(int64(config.XDPoS.Epoch*7)), header6300.ParentHash, masternodes)
|
||||
|
|
|
|||
163
consensus/tests/reward_test.go
Normal file
163
consensus/tests/reward_test.go
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/eth/hooks"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHookRewardV2(t *testing.T) {
|
||||
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
||||
assert.Nil(t, err)
|
||||
configString := string(b)
|
||||
|
||||
var config params.ChainConfig
|
||||
err = json.Unmarshal([]byte(configString), &config)
|
||||
assert.Nil(t, err)
|
||||
// set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs
|
||||
config.XDPoS.V2.SwitchBlock.SetUint64(1800)
|
||||
|
||||
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)*5, &config, 0)
|
||||
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
hooks.AttachConsensusV2Hooks(adaptor, blockchain, &config)
|
||||
assert.NotNil(t, adaptor.EngineV2.HookReward)
|
||||
// forcely insert signing tx into cache, to give rewards.
|
||||
header915 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 15)
|
||||
header916 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 16)
|
||||
header1799 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*2 - 1)
|
||||
header1801 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*2 + 1)
|
||||
tx, err := signingTxWithSignerFn(header915, 0, signer, signFn)
|
||||
assert.Nil(t, err)
|
||||
adaptor.CacheSigningTxs(header916.Hash(), []*types.Transaction{tx})
|
||||
statedb, err := blockchain.StateAt(header1799.Root)
|
||||
assert.Nil(t, err)
|
||||
parentState := statedb.Copy()
|
||||
reward, err := adaptor.EngineV2.HookReward(blockchain, statedb, parentState, header1801)
|
||||
assert.Nil(t, err)
|
||||
assert.Zero(t, len(reward))
|
||||
header2699 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*3 - 1)
|
||||
header2700 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch * 3)
|
||||
statedb, err = blockchain.StateAt(header2699.Root)
|
||||
assert.Nil(t, err)
|
||||
parentState = statedb.Copy()
|
||||
reward, err = adaptor.EngineV2.HookReward(blockchain, statedb, parentState, header2700)
|
||||
assert.Nil(t, err)
|
||||
owner := state.GetCandidateOwner(parentState, signer)
|
||||
result := reward["rewards"].(map[common.Address]interface{})
|
||||
assert.Equal(t, 1, len(result))
|
||||
for _, x := range result {
|
||||
r := x.(map[common.Address]*big.Int)
|
||||
a, _ := big.NewInt(0).SetString("225000000000000000000", 10)
|
||||
assert.Zero(t, a.Cmp(r[owner]))
|
||||
b, _ := big.NewInt(0).SetString("25000000000000000000", 10)
|
||||
assert.Zero(t, b.Cmp(r[common.HexToAddress("0x0000000000000000000000000000000000000068")]))
|
||||
}
|
||||
header2685 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*2 + 885)
|
||||
header2716 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*3 + 16)
|
||||
header3599 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*4 - 1)
|
||||
header3600 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch * 4)
|
||||
tx, err = signingTxWithSignerFn(header2685, 0, signer, signFn)
|
||||
assert.Nil(t, err)
|
||||
// signed block hash and block contains tx are in different epoch, we should get same rewards
|
||||
adaptor.CacheSigningTxs(header2716.Hash(), []*types.Transaction{tx})
|
||||
statedb, err = blockchain.StateAt(header3599.Root)
|
||||
assert.Nil(t, err)
|
||||
parentState = statedb.Copy()
|
||||
reward, err = adaptor.EngineV2.HookReward(blockchain, statedb, parentState, header3600)
|
||||
assert.Nil(t, err)
|
||||
result = reward["rewards"].(map[common.Address]interface{})
|
||||
assert.Equal(t, 1, len(result))
|
||||
for _, x := range result {
|
||||
r := x.(map[common.Address]*big.Int)
|
||||
a, _ := big.NewInt(0).SetString("225000000000000000000", 10)
|
||||
assert.Zero(t, a.Cmp(r[owner]))
|
||||
b, _ := big.NewInt(0).SetString("25000000000000000000", 10)
|
||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]))
|
||||
}
|
||||
// if no signing tx, then reward will be 0
|
||||
header4499 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*5 - 1)
|
||||
header4500 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch * 5)
|
||||
statedb, err = blockchain.StateAt(header4499.Root)
|
||||
assert.Nil(t, err)
|
||||
parentState = statedb.Copy()
|
||||
reward, err = adaptor.EngineV2.HookReward(blockchain, statedb, parentState, header4500)
|
||||
assert.Nil(t, err)
|
||||
result = reward["rewards"].(map[common.Address]interface{})
|
||||
assert.Equal(t, 0, len(result))
|
||||
}
|
||||
|
||||
func TestHookRewardV2SplitReward(t *testing.T) {
|
||||
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
||||
assert.Nil(t, err)
|
||||
configString := string(b)
|
||||
|
||||
var config params.ChainConfig
|
||||
err = json.Unmarshal([]byte(configString), &config)
|
||||
assert.Nil(t, err)
|
||||
// set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs
|
||||
config.XDPoS.V2.SwitchBlock.SetUint64(1800)
|
||||
|
||||
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)*3, &config, 0)
|
||||
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
hooks.AttachConsensusV2Hooks(adaptor, blockchain, &config)
|
||||
assert.NotNil(t, adaptor.EngineV2.HookReward)
|
||||
// forcely insert signing tx into cache, to give rewards.
|
||||
header915 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 15)
|
||||
header916 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 16)
|
||||
// header917 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 17)
|
||||
header1785 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*2 - 15)
|
||||
header1799 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*2 - 1)
|
||||
header1801 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*2 + 1)
|
||||
tx, err := signingTxWithSignerFn(header915, 0, signer, signFn)
|
||||
assert.Nil(t, err)
|
||||
adaptor.CacheSigningTxs(header916.Hash(), []*types.Transaction{tx})
|
||||
tx2, err := signingTxWithKey(header915, 0, acc1Key)
|
||||
assert.Nil(t, err)
|
||||
tx3, err := signingTxWithKey(header1785, 0, acc1Key)
|
||||
assert.Nil(t, err)
|
||||
adaptor.CacheSigningTxs(header1799.Hash(), []*types.Transaction{tx2, tx3})
|
||||
|
||||
statedb, err := blockchain.StateAt(header1799.Root)
|
||||
assert.Nil(t, err)
|
||||
parentState := statedb.Copy()
|
||||
reward, err := adaptor.EngineV2.HookReward(blockchain, statedb, parentState, header1801)
|
||||
assert.Nil(t, err)
|
||||
assert.Zero(t, len(reward))
|
||||
header2699 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*3 - 1)
|
||||
header2700 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch * 3)
|
||||
statedb, err = blockchain.StateAt(header2699.Root)
|
||||
assert.Nil(t, err)
|
||||
parentState = statedb.Copy()
|
||||
reward, err = adaptor.EngineV2.HookReward(blockchain, statedb, parentState, header2700)
|
||||
assert.Nil(t, err)
|
||||
result := reward["rewards"].(map[common.Address]interface{})
|
||||
assert.Equal(t, 2, len(result))
|
||||
// two signing account, 3 txs, reward is split by 1:2 (total reward is 250...000)
|
||||
for addr, x := range result {
|
||||
if addr == acc1Addr {
|
||||
r := x.(map[common.Address]*big.Int)
|
||||
owner := state.GetCandidateOwner(parentState, acc1Addr)
|
||||
a, _ := big.NewInt(0).SetString("149999999999999999999", 10)
|
||||
assert.Zero(t, a.Cmp(r[owner]))
|
||||
b, _ := big.NewInt(0).SetString("16666666666666666666", 10)
|
||||
assert.Zero(t, b.Cmp(r[common.HexToAddress("0x0000000000000000000000000000000000000068")]))
|
||||
} else if addr == signer {
|
||||
r := x.(map[common.Address]*big.Int)
|
||||
owner := state.GetCandidateOwner(parentState, signer)
|
||||
a, _ := big.NewInt(0).SetString("74999999999999999999", 10)
|
||||
assert.Zero(t, a.Cmp(r[owner]))
|
||||
b, _ := big.NewInt(0).SetString("8333333333333333333", 10)
|
||||
assert.Zero(t, b.Cmp(r[common.HexToAddress("0x0000000000000000000000000000000000000068")]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -230,7 +230,7 @@ func voteTX(gasLimit uint64, nonce uint64, addr string) (*types.Transaction, err
|
|||
return signedTX, nil
|
||||
}
|
||||
|
||||
func signingTx(header *types.Header, nonce uint64, signer common.Address, signFn func(account accounts.Account, hash []byte) ([]byte, error)) (*types.Transaction, error) {
|
||||
func signingTxWithSignerFn(header *types.Header, nonce uint64, signer common.Address, signFn func(account accounts.Account, hash []byte) ([]byte, error)) (*types.Transaction, error) {
|
||||
tx := contracts.CreateTxSign(header.Number, header.Hash(), nonce, common.HexToAddress(common.BlockSigners))
|
||||
s := types.NewEIP155Signer(big.NewInt(chainID))
|
||||
h := s.Hash(tx)
|
||||
|
|
@ -245,6 +245,21 @@ func signingTx(header *types.Header, nonce uint64, signer common.Address, signFn
|
|||
return signedTx, nil
|
||||
}
|
||||
|
||||
func signingTxWithKey(header *types.Header, nonce uint64, privateKey *ecdsa.PrivateKey) (*types.Transaction, error) {
|
||||
tx := contracts.CreateTxSign(header.Number, header.Hash(), nonce, common.HexToAddress(common.BlockSigners))
|
||||
s := types.NewEIP155Signer(big.NewInt(chainID))
|
||||
h := s.Hash(tx)
|
||||
sig, err := crypto.Sign(h[:], privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signedTx, err := tx.WithSignature(s, sig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return signedTx, nil
|
||||
}
|
||||
|
||||
func UpdateSigner(bc *BlockChain) error {
|
||||
err := bc.UpdateM1()
|
||||
return err
|
||||
|
|
@ -534,8 +549,8 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
|
|||
Coinbase: common.HexToAddress(blockCoinBase),
|
||||
}
|
||||
|
||||
// Inject the hardcoded master node list for the last v1 epoch block
|
||||
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 0 {
|
||||
// Inject the hardcoded master node list for the last v1 epoch block and all v1 epoch switch blocks (excluding genesis)
|
||||
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
|
||||
// reset extra
|
||||
header.Extra = []byte{}
|
||||
if len(header.Extra) < utils.ExtraVanity {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
|
|||
blockInfo := &utils.BlockInfo{
|
||||
Hash: currentBlock.Hash(),
|
||||
Round: utils.Round(1),
|
||||
Number: big.NewInt(11),
|
||||
Number: big.NewInt(901),
|
||||
}
|
||||
voteSigningHash := utils.VoteSigHash(blockInfo)
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ const (
|
|||
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
)
|
||||
|
||||
type rewardLog struct {
|
||||
type RewardLog struct {
|
||||
Sign uint64 `json:"sign"`
|
||||
Reward *big.Int `json:"reward"`
|
||||
}
|
||||
|
|
@ -319,13 +319,13 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte)
|
|||
}
|
||||
|
||||
// Calculate reward for reward checkpoint.
|
||||
func GetRewardForCheckpoint(c *XDPoS.XDPoS, chain consensus.ChainReader, header *types.Header, rCheckpoint uint64, totalSigner *uint64) (map[common.Address]*rewardLog, error) {
|
||||
func GetRewardForCheckpoint(c *XDPoS.XDPoS, chain consensus.ChainReader, header *types.Header, rCheckpoint uint64, totalSigner *uint64) (map[common.Address]*RewardLog, error) {
|
||||
// Not reward for singer of genesis block and only calculate reward at checkpoint block.
|
||||
number := header.Number.Uint64()
|
||||
prevCheckpoint := number - (rCheckpoint * 2)
|
||||
startBlockNumber := prevCheckpoint + 1
|
||||
endBlockNumber := startBlockNumber + rCheckpoint - 1
|
||||
signers := make(map[common.Address]*rewardLog)
|
||||
signers := make(map[common.Address]*RewardLog)
|
||||
mapBlkHash := map[uint64]common.Hash{}
|
||||
|
||||
data := make(map[common.Hash][]common.Address)
|
||||
|
|
@ -376,7 +376,7 @@ func GetRewardForCheckpoint(c *XDPoS.XDPoS, chain consensus.ChainReader, header
|
|||
if exist {
|
||||
signers[addr].Sign++
|
||||
} else {
|
||||
signers[addr] = &rewardLog{1, new(big.Int)}
|
||||
signers[addr] = &RewardLog{1, new(big.Int)}
|
||||
}
|
||||
*totalSigner++
|
||||
}
|
||||
|
|
@ -390,7 +390,7 @@ func GetRewardForCheckpoint(c *XDPoS.XDPoS, chain consensus.ChainReader, header
|
|||
}
|
||||
|
||||
// Calculate reward for signers.
|
||||
func CalculateRewardForSigner(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)
|
||||
// Add reward for signers.
|
||||
if totalSigner > 0 {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
package hooks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/contracts"
|
||||
"github.com/XinFinOrg/XDPoSChain/core"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/eth/util"
|
||||
"github.com/XinFinOrg/XDPoSChain/log"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
)
|
||||
|
|
@ -135,4 +139,139 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
|||
return penalties, nil
|
||||
}
|
||||
|
||||
// Hook calculates reward for masternodes
|
||||
adaptor.EngineV2.HookReward = func(chain consensus.ChainReader, stateBlock *state.StateDB, parentState *state.StateDB, header *types.Header) (map[string]interface{}, error) {
|
||||
number := header.Number.Uint64()
|
||||
foundationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr
|
||||
if foundationWalletAddr == (common.Address{}) {
|
||||
log.Error("Foundation Wallet Address is empty", "error", foundationWalletAddr)
|
||||
return nil, errors.New("foundation wallet address is empty")
|
||||
}
|
||||
rewards := make(map[string]interface{})
|
||||
// skip hook reward if this is the first v2
|
||||
if number == chain.Config().XDPoS.V2.SwitchBlock.Uint64()+1 {
|
||||
return rewards, nil
|
||||
}
|
||||
start := time.Now()
|
||||
// Get reward inflation.
|
||||
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().XDPoS.Reward), new(big.Int).SetUint64(params.Ether))
|
||||
chainReward = util.RewardInflation(chain, chainReward, number, common.BlocksPerYear)
|
||||
|
||||
// Get signers/signing tx count
|
||||
totalSigner := new(uint64)
|
||||
signers, err := GetSigningTxCount(adaptor, chain, header, totalSigner)
|
||||
|
||||
log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
||||
if err != nil {
|
||||
log.Error("[HookReward] Fail to get signers count for reward checkpoint", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
rewards["signers"] = signers
|
||||
rewardSigners, err := contracts.CalculateRewardForSigner(chainReward, signers, *totalSigner)
|
||||
if err != nil {
|
||||
log.Error("[HookReward] Fail to calculate reward for signers", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
// Add reward for coin holders.
|
||||
voterResults := make(map[common.Address]interface{})
|
||||
if len(signers) > 0 {
|
||||
for signer, calcReward := range rewardSigners {
|
||||
err, rewards := contracts.CalculateRewardForHolders(foundationWalletAddr, parentState, signer, calcReward, number)
|
||||
if err != nil {
|
||||
log.Error("[HookReward] Fail to calculate reward for holders.", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
if len(rewards) > 0 {
|
||||
for holder, reward := range rewards {
|
||||
stateBlock.AddBalance(holder, reward)
|
||||
}
|
||||
}
|
||||
voterResults[signer] = rewards
|
||||
}
|
||||
}
|
||||
rewards["rewards"] = voterResults
|
||||
log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
||||
return rewards, nil
|
||||
}
|
||||
}
|
||||
|
||||
// get signing transaction sender count
|
||||
func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *types.Header, totalSigner *uint64) (map[common.Address]*contracts.RewardLog, error) {
|
||||
// header should be a new epoch switch block
|
||||
number := header.Number.Uint64()
|
||||
rewardEpochCount := 2
|
||||
signEpochCount := 1
|
||||
signers := make(map[common.Address]*contracts.RewardLog)
|
||||
mapBlkHash := map[uint64]common.Hash{}
|
||||
|
||||
data := make(map[common.Hash][]common.Address)
|
||||
epochCount := 0
|
||||
var masternodes []common.Address
|
||||
var startBlockNumber, endBlockNumber uint64
|
||||
for i := number - 1; ; i-- {
|
||||
header = chain.GetHeader(header.ParentHash, i)
|
||||
isEpochSwitch, _, err := c.IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isEpochSwitch && i != chain.Config().XDPoS.V2.SwitchBlock.Uint64()+1 {
|
||||
epochCount += 1
|
||||
if epochCount == signEpochCount {
|
||||
endBlockNumber = header.Number.Uint64() - 1
|
||||
}
|
||||
if epochCount == rewardEpochCount {
|
||||
startBlockNumber = header.Number.Uint64() + 1
|
||||
masternodes = c.GetMasternodesFromCheckpointHeader(header)
|
||||
break
|
||||
}
|
||||
}
|
||||
mapBlkHash[i] = header.Hash()
|
||||
signData, ok := c.GetCachedSigningTxs(header.Hash())
|
||||
if !ok {
|
||||
log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i)
|
||||
block := chain.GetBlock(header.Hash(), i)
|
||||
txs := block.Transactions()
|
||||
signData = c.CacheSigningTxs(header.Hash(), txs)
|
||||
}
|
||||
txs := signData.([]*types.Transaction)
|
||||
for _, tx := range txs {
|
||||
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
|
||||
from := *tx.From()
|
||||
data[blkHash] = append(data[blkHash], from)
|
||||
}
|
||||
}
|
||||
|
||||
for i := startBlockNumber; i <= endBlockNumber; i++ {
|
||||
if i%common.MergeSignRange == 0 {
|
||||
addrs := data[mapBlkHash[i]]
|
||||
// Filter duplicate address.
|
||||
if len(addrs) > 0 {
|
||||
addrSigners := make(map[common.Address]bool)
|
||||
for _, masternode := range masternodes {
|
||||
for _, addr := range addrs {
|
||||
if addr == masternode {
|
||||
if _, ok := addrSigners[addr]; !ok {
|
||||
addrSigners[addr] = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for addr := range addrSigners {
|
||||
_, exist := signers[addr]
|
||||
if exist {
|
||||
signers[addr].Sign++
|
||||
} else {
|
||||
signers[addr] = &contracts.RewardLog{Sign: 1, Reward: new(big.Int)}
|
||||
}
|
||||
*totalSigner++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
|
||||
|
||||
return signers, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ var (
|
|||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
|
||||
|
||||
// XDPoS config with v2 engine after block 901
|
||||
TestXDPoSMockChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true, V2: TestXDPoSV2Config}}
|
||||
TestXDPoSMockChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true, V2: TestXDPoSV2Config, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"), Reward: 250}}
|
||||
|
||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
|
|
|
|||
Loading…
Reference in a new issue