From 5a51506652511b8d548186204cd38b16701c5fa4 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 09:57:50 +0000 Subject: [PATCH] cache votercap --- common/types.go | 9 ++++ consensus/posv/posv.go | 54 +++++++++++----------- contracts/utils.go | 97 +++++++++++++++++++++++++++++---------- core/types/transaction.go | 38 +++++++++++++++ eth/backend.go | 4 +- 5 files changed, 146 insertions(+), 56 deletions(-) diff --git a/common/types.go b/common/types.go index 871700758e..ad06240675 100644 --- a/common/types.go +++ b/common/types.go @@ -35,6 +35,10 @@ const ( RandomizeSMC = "0x0000000000000000000000000000000000000090" FoudationAddr = "0x0000000000000000000000000000000000000068" TeamAddr = "0x0000000000000000000000000000000000000099" + VoteMethod = "0x6dd7d8ea" + UnvoteMethod = "0x02aa9be2" + ProposeMethod = "0x01267951" + ResignMethod = "0xae6e43f5" ) var ( @@ -45,6 +49,11 @@ var ( // Hash represents the 32 byte Keccak256 hash of arbitrary data. type Hash [HashLength]byte +type Vote struct { + Masternode Address + Voter Address +} + func BytesToHash(b []byte) Hash { var h Hash h.SetBytes(b) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 7129c19475..b196707201 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -53,6 +53,7 @@ import ( const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory blockSignersCacheLimit = 3600 + votingCacheLimit = 1500000 M2ByteLength = 4 ) @@ -228,7 +229,9 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields + EnableCache bool BlockSigners *lru.ARCCache + Votes *lru.ARCCache HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) @@ -245,6 +248,7 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { } // Allocate the snapshot caches and create the engine BlockSigners, _ := lru.NewARC(blockSignersCacheLimit) + Votes, _ := lru.NewARC(votingCacheLimit) recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySnapshots) validatorSignatures, _ := lru.NewARC(inmemorySnapshots) @@ -252,7 +256,9 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { return &Posv{ config: &conf, db: db, + EnableCache: false, BlockSigners: BlockSigners, + Votes: Votes, recents: recents, signatures: signatures, verifiedHeaders: verifiedHeaders, @@ -261,10 +267,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { } } -func (c *Posv) GetBlockSigners() *lru.ARCCache { - return c.BlockSigners -} - // Author implements consensus.Engine, returning the Ethereum address recovered // from the signature in the header's extra-data section. func (c *Posv) Author(header *types.Header) (common.Address, error) { @@ -860,42 +862,38 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - /* - abiJSON := `[{"inputs":[{"name":"_blockNumber","type":"uint256"},{"name":"_blockHash","type":"bytes32"}],"name":"sign","type":"function"}]` - abiReader, err := abi.JSON(strings.NewReader(abiJSON)) - if err != nil { - log.Error("Abi parser error", err) - } - - type Sign struct { - BlockNumber *big.Int - BlockHash common.Hash - } - var s Sign - */ - + start := time.Now() for _, tx := range txs { if tx.IsSigningTransaction() { - /* - err = abiReader.Unpack(&s, "sign", tx.Data()) - if err != nil { - log.Error("Abi unpack error", err) - } - blkHash := s.BlockHash - */ blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - txHash := *tx.From() + from := *tx.From() var lAddr []common.Address if cached, ok := c.BlockSigners.Get(blkHash); ok { lAddr = cached.([]common.Address) - lAddr = append(lAddr, txHash) + lAddr = append(lAddr, from) } else { - lAddr = []common.Address{txHash} + lAddr = []common.Address{from} } c.BlockSigners.Add(blkHash, lAddr) + } else { + + b, addr := tx.IsVotingTransaction() + if b && addr != nil { + var vote common.Vote + vote.Masternode = *addr + vote.Voter = *tx.From() + + c.Votes.Remove(vote) + } } } + fmt.Println("Time Calculate Cache", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) + + if !c.EnableCache && c.BlockSigners.Len() >= 1800 { + fmt.Println("EnableCache true") + c.EnableCache = true + } if c.HookReward != nil && number%rCheckpoint == 0 { err, rewards := c.HookReward(chain, state, header) diff --git a/contracts/utils.go b/contracts/utils.go index 6df27772f2..17059a6c8f 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -201,7 +201,7 @@ func GetSignersFromContract(c *posv.Posv, addrBlockSigner common.Address, client log.Error("Fail get instance of blockSigner", "error", err) return nil, err } - if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || c.BlockSigners.Len() < 1800 { + if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || !c.EnableCache { opts := new(bind.CallOpts) addrs, err := blockSigner.GetSigners(opts, blockHash) if err != nil { @@ -315,25 +315,14 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign if len(masternodes) > 0 { - var wg sync.WaitGroup - squeue := make(chan []common.Address, 1) - wg.Add(900) - - for i := startBlockNumber; i <= endBlockNumber; i++ { - go func(i uint64) { + if !c.EnableCache { + for i := startBlockNumber; i <= endBlockNumber; i++ { block := chain.GetHeaderByNumber(i) addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) - // addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) if err != nil { - log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - // return nil, err + log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) + return nil, err } - squeue <- addrs - }(i) - } - - fsigner := func() { - for addrs := range squeue { // Filter duplicate address. if len(addrs) > 0 { addrSigners := make(map[common.Address]bool) @@ -358,13 +347,60 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign *totalSigner++ } } - wg.Done() } + } else { + var wg sync.WaitGroup + squeue := make(chan []common.Address, 1) + wg.Add(900) + + for i := startBlockNumber; i <= endBlockNumber; i++ { + go func(i uint64) { + block := chain.GetHeaderByNumber(i) + addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) + // addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) + if err != nil { + log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) + // return nil, err + } + squeue <- addrs + }(i) + } + + fsigner := func() { + for addrs := range squeue { + // 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] = &rewardLog{1, new(big.Int)} + } + *totalSigner++ + } + } + wg.Done() + } + } + + go fsigner() + + wg.Wait() } - - go fsigner() - - wg.Wait() + fmt.Println("c.BlockSigners.Len()", c.BlockSigners.Len()) fmt.Println("totalSigner", *totalSigner) } @@ -411,8 +447,8 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign } // Calculate reward for holders. -func CalculateRewardForHolders(foudationWalletAddr common.Address, validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { - rewards, err := GetRewardBalancesRate(foudationWalletAddr, signer, calcReward, validator) +func CalculateRewardForHolders(c *posv.Posv, foudationWalletAddr common.Address, validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { + rewards, err := GetRewardBalancesRate(c, foudationWalletAddr, signer, calcReward, validator) if err != nil { return err, nil } @@ -425,7 +461,7 @@ func CalculateRewardForHolders(foudationWalletAddr common.Address, validator *co } // Get reward balance rates for master node, founder and holders. -func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) { +func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (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(common.RewardMasterPercent)) @@ -446,7 +482,18 @@ func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common // Get voters capacities. voterCaps := make(map[common.Address]*big.Int) for _, voteAddr := range voters { - voterCap, err := validator.GetVoterCap(opts, masterAddr, voteAddr) + var vote common.Vote + var voterCap *big.Int + + vote.Masternode = masterAddr + vote.Voter = voteAddr + + if vCap, ok := c.Votes.Get(vote); ok { + voterCap = vCap.(*big.Int) + } else { + voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + c.Votes.Add(vote, voterCap) + } if err != nil { log.Error("Fail to get vote capacity", "error", err) return nil, err diff --git a/core/types/transaction.go b/core/types/transaction.go index d7c8c3086b..9bc42013b0 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -294,6 +294,44 @@ func (tx *Transaction) IsSigningTransaction() bool { return tx.To().String() == common.BlockSigners } +func (tx *Transaction) IsVotingTransaction() (bool, *common.Address) { + if tx.To() == nil { + return false, nil + } + b := (tx.To().String() == common.MasternodeVotingSMC) + + if !b { + return b, nil + } + + method := common.ToHex(tx.Data()[0:4]) + if b = (method == common.VoteMethod); b { + addr := tx.Data()[len(tx.Data())-20:] + m := common.BytesToAddress(addr) + return b, &m + } + + if b = (method == common.UnvoteMethod); b { + addr := tx.Data()[len(tx.Data())-32-20 : len(tx.Data())-32] + m := common.BytesToAddress(addr) + return b, &m + } + + if b = (method == common.ProposeMethod); b { + addr := tx.Data()[len(tx.Data())-20:] + m := common.BytesToAddress(addr) + return b, &m + } + + if b = (method == common.ResignMethod); b { + addr := tx.Data()[len(tx.Data())-20:] + m := common.BytesToAddress(addr) + return b, &m + } + + return b, nil +} + func (tx *Transaction) String() string { var from, to string if tx.data.V != nil { diff --git a/eth/backend.go b/eth/backend.go index d5ee7ab205..131bc88748 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -327,10 +327,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Add reward for coin holders. voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { - // vmenv := core.NewRuntimeEVM(state) for signer, calcReward := range rewardSigners { - err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) - // err, rewards := contracts.CalculateRewardForHolders2(foudationWalletAddr, vmenv, state, signer, calcReward) + err, rewards := contracts.CalculateRewardForHolders(c, foudationWalletAddr, validator, state, signer, calcReward) if err != nil { log.Crit("Fail to calculate reward for holders.", "error", err) }