diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 37db23d45f..edbbc1cfae 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -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) } diff --git a/consensus/tests/penalty_test.go b/consensus/tests/penalty_test.go index 25d73b9f79..cae4b82687 100644 --- a/consensus/tests/penalty_test.go +++ b/consensus/tests/penalty_test.go @@ -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) diff --git a/consensus/tests/reward_test.go b/consensus/tests/reward_test.go new file mode 100644 index 0000000000..34a7165539 --- /dev/null +++ b/consensus/tests/reward_test.go @@ -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")])) + } + } +} diff --git a/consensus/tests/test_helper.go b/consensus/tests/test_helper.go index f3c08ccf26..316db30ec3 100644 --- a/consensus/tests/test_helper.go +++ b/consensus/tests/test_helper.go @@ -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 { diff --git a/consensus/tests/vote_test.go b/consensus/tests/vote_test.go index 6aa9b67626..b9ff4cf666 100644 --- a/consensus/tests/vote_test.go +++ b/consensus/tests/vote_test.go @@ -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) diff --git a/contracts/utils.go b/contracts/utils.go index d521049884..40fd7bda99 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -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 { diff --git a/eth/hooks/engine_v2_hooks.go b/eth/hooks/engine_v2_hooks.go index 8aa18b8e49..ac591f15e9 100644 --- a/eth/hooks/engine_v2_hooks.go +++ b/eth/hooks/engine_v2_hooks.go @@ -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 } diff --git a/params/config.go b/params/config.go index 1cd5920c9a..73f04cc114 100644 --- a/params/config.go +++ b/params/config.go @@ -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))