From 831626de231adb2a2d610e2916dd0349701e32e6 Mon Sep 17 00:00:00 2001 From: MestryOmkar Date: Sat, 4 Aug 2018 14:11:24 +0530 Subject: [PATCH] Add reward for signers and validators for reward checkpoint. --- consensus/clique/clique.go | 61 +++------------------- eth/backend.go | 102 +++++++++++++++++++++++++++++++++++++ node/service.go | 5 ++ 3 files changed, 113 insertions(+), 55 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index d3b485465a..284f338b2a 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -25,7 +25,6 @@ import ( "sync" "time" - "encoding/json" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -208,6 +207,8 @@ type Clique struct { signer common.Address // Ethereum address of the signing key signFn SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields + + HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error } // New creates a Clique proof-of-authority consensus engine with the initial @@ -606,8 +607,10 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro func (c *Clique) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // set block reward // FIXME: unit Ether could be too plump - if err := c.accumulateRewards(chain, state, header); err != nil { - return nil, err + if c.HookReward != nil { + if error := c.HookReward(chain, state, header); error != nil { + return nil, error + } } // No block rewards in PoA, so the state remains as is and uncles are dropped @@ -724,58 +727,6 @@ func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API { }} } -func (c *Clique) accumulateRewards(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error { - type rewardLog struct { - Sign uint64 `json:"sign"` - Reward float64 `json:"reward"` - } - - number := header.Number.Uint64() - rCheckpoint := chain.Config().Clique.RewardCheckpoint - - if number > 0 && rCheckpoint > 0 && number%rCheckpoint == 0 { - // Not reward for singer of genesis block and only calculate reward at checkpoint block. - parentHeader := chain.GetHeaderByHash(header.ParentHash) - startBlockNumber := number - rCheckpoint + 1 - endBlockNumber := parentHeader.Number.Uint64() - signers := make(map[common.Address]*rewardLog) - totalSigner := uint64(0) - - for i := startBlockNumber; i <= endBlockNumber; i++ { - blockHeader := chain.GetHeaderByNumber(i) - if signer, err := ecrecover(blockHeader, c.signatures); err != nil { - return err - } else { - _, exist := signers[signer] - if exist { - signers[signer].Sign++ - } else { - signers[signer] = &rewardLog{1, 0} - } - totalSigner++ - } - } - - chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether) - // Update balance reward. - calcReward := new(big.Int) - for signer, rLog := range signers { - calcReward.Mul(chainReward, new(big.Int).SetUint64(rLog.Sign)) - calcReward.Div(calcReward, new(big.Int).SetUint64(totalSigner)) - rLog.Reward = float64(calcReward.Int64()) - - state.AddBalance(signer, calcReward) - } - jsonSigners, err := json.Marshal(signers) - if err != nil { - return err - } - log.Info("XDC - Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber, "signers", string(jsonSigners), "totalSigner", totalSigner, "totalReward", chainReward) - } - - return nil -} - func (c *Clique) RecoverSigner(header *types.Header) (common.Address, error) { return ecrecover(header, c.signatures) } \ No newline at end of file diff --git a/eth/backend.go b/eth/backend.go index fb2d302f9f..019e7fb7c9 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -25,19 +25,24 @@ import ( "sync" "sync/atomic" + "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/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/contracts/blocksigner/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -181,6 +186,103 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Inject hook for send tx sign to smartcontract after insert block into chain. eth.protocolManager.fetcher.CreateTransactionSign(eth.chainConfig, eth.txPool, eth.accountManager, eth.engine) + if eth.chainConfig.Clique != nil { + c := eth.engine.(*clique.Clique) + // Hook reward for clique validator. + c.HookReward = func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error { + type rewardLog struct { + Sign uint64 `json:"sign"` + Reward float64 `json:"reward"` + } + + // Call to smart contract signer. + config := ctx.GetConfig() + client, err := ethclient.Dial(config.IPCEndpoint()) + if err != nil { + log.Error("XDC - Fail to connect RPC", "error", err) + } + addr := common.HexToAddress(common.BlockSigners) + blockSigner, err := contract.NewBlockSigner(addr, client) + if err != nil { + log.Error("XDC - Fail get block signer", "error", err) + } + opts := new(bind.CallOpts) + + number := header.Number.Uint64() + rCheckpoint := chain.Config().Clique.RewardCheckpoint + prevCheckpoint := number - rCheckpoint + + if number > 0 && prevCheckpoint > 0 && number%rCheckpoint == 0 { + // Not reward for singer of genesis block and only calculate reward at checkpoint block. + startBlockNumber := number - (rCheckpoint * 2) + 1 + endBlockNumber := startBlockNumber + rCheckpoint - 2 + signers := make(map[common.Address]*rewardLog) + validators := make(map[common.Address]*rewardLog) + totalSigner := uint64(0) + + for i := startBlockNumber; i <= endBlockNumber; i++ { + blockHeader := chain.GetHeaderByNumber(i) + if signer, err := c.RecoverSigner(blockHeader); err != nil { + return err + } else { + _, exist := signers[signer] + if exist { + signers[signer].Sign++ + } else { + signers[signer] = &rewardLog{1, 0} + } + totalSigner++ + } + + // Get validator in blockSigner smartcontract. + addrs, _ := blockSigner.GetSigners(opts, new(big.Int).SetUint64(i)) + if len(addrs) > 0 { + for j := 0; j < len(addrs); j++ { + _, exist := validators[addrs[j]] + if exist { + validators[addrs[j]].Sign++ + } else { + validators[addrs[j]] = &rewardLog{1, 0} + } + totalSigner++ + } + } + } + + chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether) + // Add reward for signer. + calcReward := new(big.Int) + for signer, rLog := range signers { + calcReward.Mul(chainReward, new(big.Int).SetUint64(rLog.Sign)) + calcReward.Div(calcReward, new(big.Int).SetUint64(totalSigner)) + rLog.Reward = float64(calcReward.Int64()) + + state.AddBalance(signer, calcReward) + } + // Add reward for validators. + for validator, rLog := range validators { + calcReward.Mul(chainReward, new(big.Int).SetUint64(rLog.Sign)) + calcReward.Div(calcReward, new(big.Int).SetUint64(totalSigner)) + rLog.Reward = float64(calcReward.Int64()) + + state.AddBalance(validator, calcReward) + } + jsonSigners, err := json.Marshal(signers) + if err != nil { + return err + } + jsonValidators, err := json.Marshal(validators) + if err != nil { + return err + } + + log.Info("XDC - Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber, "signers", string(jsonSigners), "totalSigner", totalSigner, "totalReward", chainReward, "validators", string(jsonValidators)) + } + + return nil + } + } + return eth, nil } diff --git a/node/service.go b/node/service.go index 55062a5004..1132d9e1c3 100644 --- a/node/service.go +++ b/node/service.go @@ -67,6 +67,11 @@ func (ctx *ServiceContext) Service(service interface{}) error { return ErrServiceUnknown } +// Get current node config. +func (ctx *ServiceContext) GetConfig() *Config { + return ctx.config +} + // ServiceConstructor is the function signature of the constructors needed to be // registered for service instantiation. type ServiceConstructor func(ctx *ServiceContext) (Service, error)