From 73efc02259ff9d1ae0bed8a5cc9a228ba1757f60 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 10 Jan 2019 09:50:45 +0000 Subject: [PATCH] refactor cache BlockSigners --- consensus/posv/posv.go | 52 ++++++------ contracts/utils.go | 112 +++++++++----------------- contracts/validator/validator_test.go | 2 +- eth/backend.go | 2 +- internal/ethapi/api.go | 2 +- 5 files changed, 66 insertions(+), 104 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index f38fb6932e..d30a4f2b32 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -50,7 +50,6 @@ import ( const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory blockSignersCacheLimit = 36000 - votingCacheLimit = 1500000 M2ByteLength = 4 ) @@ -245,7 +244,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { } // Allocate the snapshot caches and create the engine BlockSigners, _ := lru.New(blockSignersCacheLimit) - Votes, _ := lru.New(votingCacheLimit) recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySnapshots) validatorSignatures, _ := lru.NewARC(inmemorySnapshots) @@ -255,7 +253,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { db: db, EnableCache: false, BlockSigners: BlockSigners, - Votes: Votes, recents: recents, signatures: signatures, verifiedHeaders: verifiedHeaders, @@ -880,7 +877,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } - _ = c.cacheData(txs, receipts) + _ = c.cacheData(header, txs, receipts) // the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) @@ -1036,12 +1033,10 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea return masternodes } -func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) error { +func (c *Posv) cacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) error { + var signTxs []*types.Transaction for _, tx := range txs { if tx.IsSigningTransaction() { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - var b uint for _, r := range receipts { if r.TxHash == tx.Hash() { @@ -1054,31 +1049,34 @@ func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) er continue } - var lAddr []common.Address - if cached, ok := c.BlockSigners.Get(blkHash); ok { - lAddr = cached.([]common.Address) - lAddr = append(lAddr, from) - } else { - 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() - - log.Debug("Remove from Votes cache ", "Masternode", vote.Masternode.String(), "Voter", vote.Voter.String()) - c.Votes.Remove(vote) - } + signTxs = append(signTxs, tx) } } + c.BlockSigners.Add(header.Hash(), signTxs) + return nil } +func (c *Posv) GetSignData(chain consensus.ChainReader, startBlockNumber uint64, endBlockNumber uint64) (map[common.Hash][]common.Address, error) { + data := make(map[common.Hash][]common.Address) + for i := startBlockNumber; i < chain.CurrentHeader().Number.Uint64(); i++ { + block := chain.GetHeaderByNumber(i) + + if signData, ok := c.BlockSigners.Get(block.Hash()); ok { + 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) + } + } else { + return nil, errors.New("Failed get blocksigners from cache") + } + } + return data, nil +} + // Extract validators from byte array. func RemovePenaltiesFromBlock(chain consensus.ChainReader, masternodes []common.Address, epochNumber uint64) []common.Address { if epochNumber <= 0 { diff --git a/contracts/utils.go b/contracts/utils.go index d40ab6945f..078a0b69be 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -199,23 +199,19 @@ func BuildTxOpeningRandomize(nonce uint64, randomizeAddr common.Address, randomi } // Get signers signed for blockNumber from blockSigner contract. -func GetSignersFromContract(c *posv.Posv, addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) { +func GetSignersFromContract(addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) { blockSigner, err := contract.NewBlockSigner(addrBlockSigner, client) if err != nil { log.Error("Fail get instance of blockSigner", "error", err) return nil, err } - if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || !c.EnableCache { - opts := new(bind.CallOpts) - addrs, err := blockSigner.GetSigners(opts, blockHash) - if err != nil { - log.Error("Fail get block signers", "error", err) - return nil, err - } - return addrs, nil - } else { - return caddrs.([]common.Address), nil + opts := new(bind.CallOpts) + addrs, err := blockSigner.GetSigners(opts, blockHash) + if err != nil { + log.Error("Fail get block signers", "error", err) + return nil, err } + return addrs, nil } // Get random from randomize contract. @@ -324,7 +320,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign if !c.EnableCache { for i := startBlockNumber; i <= endBlockNumber; i++ { block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) + addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) if err != nil { log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) return nil, err @@ -355,54 +351,39 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign } } } else { - var wg sync.WaitGroup - squeue := make(chan []common.Address, 1) - wg.Add(int(rCheckpoint)) + data, err := c.GetSignData(chain, startBlockNumber, endBlockNumber) + if err != nil { + log.Crit("Fail to get signers from cache.", "endBlockNumber", startBlockNumber, "startBlockNumber", endBlockNumber) + } for i := startBlockNumber; i <= endBlockNumber; i++ { - go func(i uint64) { - block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) - if err != nil { - log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - } - 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 + block := chain.GetHeaderByNumber(i) + addrs := data[block.Hash()] + // 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() + + for addr := range addrSigners { + _, exist := signers[addr] + if exist { + signers[addr].Sign++ + } else { + signers[addr] = &rewardLog{1, new(big.Int)} + } + *totalSigner++ + } } } - - go fsigner() - - wg.Wait() } } @@ -450,7 +431,7 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign // Calculate reward for holders. 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) + rewards, err := GetRewardBalancesRate(foudationWalletAddr, signer, calcReward, validator) if err != nil { return err, nil } @@ -463,7 +444,7 @@ func CalculateRewardForHolders(c *posv.Posv, foudationWalletAddr common.Address, } // Get reward balance rates for master node, founder and holders. -func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) { +func GetRewardBalancesRate(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)) @@ -484,28 +465,11 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas // Get voters capacities. voterCaps := make(map[common.Address]*big.Int) for _, voteAddr := range voters { - var vote common.Vote var voterCap *big.Int - vote.Masternode = masterAddr - vote.Voter = voteAddr - - if c != nil { - if vCap, ok := c.Votes.Get(vote); ok { - voterCap = vCap.(*big.Int) - } else { - voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) - if err != nil { - log.Crit("Fail to get vote capacity", "error", err) - } - log.Debug("Add to Votes cache ", "vote.Masternode", vote.Masternode.String(), "vote.Voter", vote.Voter.String(), "voterCap", voterCap.String()) - c.Votes.Add(vote, voterCap) - } - } else { - voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) - if err != nil { - log.Crit("Fail to get vote capacity", "error", err) - } + voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + if err != nil { + log.Crit("Fail to get vote capacity", "error", err) } totalCap.Add(totalCap, voterCap) diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index e5df78d42f..f3896db4b8 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -144,7 +144,7 @@ func TestRewardBalance(t *testing.T) { foundationAddr := common.HexToAddress(common.FoudationAddr) totalReward := new(big.Int).SetInt64(15 * 1000) - rewards, err := contracts.GetRewardBalancesRate(nil, foundationAddr, acc3Addr, totalReward, baseValidator) + rewards, err := contracts.GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator) if err != nil { t.Error("Fail to get reward balances rate.", err) } diff --git a/eth/backend.go b/eth/backend.go index e28231d2fb..c3fe173fad 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -259,7 +259,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { for i := prevEpoc; i < blockNumberEpoc; i++ { blockHeader := chain.GetHeaderByNumber(i) if len(penSigners) > 0 { - signedMasternodes, err := contracts.GetSignersFromContract(c, blockSignerAddr, client, blockHeader.Hash()) + signedMasternodes, err := contracts.GetSignersFromContract(blockSignerAddr, client, blockHeader.Hash()) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2c009c5b90..a9a4c816fb 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -867,7 +867,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx if b.Number().Int64() > 0 { engine := s.b.GetEngine() addrBlockSigner := common.HexToAddress(common.BlockSigners) - signers, err = contracts.GetSignersFromContract(engine.(*posv.Posv), addrBlockSigner, client, b.Hash()) + signers, err = contracts.GetSignersFromContract(addrBlockSigner, client, b.Hash()) if err != nil { log.Error("Fail to get signers from block signer SC.", "error", err) return nil, err