From 73efc02259ff9d1ae0bed8a5cc9a228ba1757f60 Mon Sep 17 00:00:00 2001
From: Nguyen Sy Thanh Son <thanhson1085@gmail.com>
Date: Thu, 10 Jan 2019 09:50:45 +0000
Subject: [PATCH 1/7] refactor cache BlockSigners

---
 consensus/posv/posv.go                |  50 ++++++------
 contracts/utils.go                    | 108 +++++++++-----------------
 contracts/validator/validator_test.go |   2 +-
 eth/backend.go                        |   2 +-
 internal/ethapi/api.go                |   2 +-
 5 files changed, 63 insertions(+), 101 deletions(-)

diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go
index f38fb6932e11..d30a4f2b32c2 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,29 +1049,32 @@ 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 {
+			signTxs = append(signTxs, tx)
+		}
+	}
 
-			b, addr := tx.IsVotingTransaction()
-			if b && addr != nil {
-				var vote common.Vote
-				vote.Masternode = *addr
-				vote.Voter = *tx.From()
+	c.BlockSigners.Add(header.Hash(), signTxs)
 
-				log.Debug("Remove from Votes cache ", "Masternode", vote.Masternode.String(), "Voter", vote.Voter.String())
-				c.Votes.Remove(vote)
+	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 nil
+	return data, nil
 }
 
 // Extract validators from byte array.
diff --git a/contracts/utils.go b/contracts/utils.go
index d40ab6945f38..078a0b69beba 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))
-
-			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)
+			data, err := c.GetSignData(chain, startBlockNumber, endBlockNumber)
+			if err != nil {
+				log.Crit("Fail to get signers from cache.", "endBlockNumber", startBlockNumber, "startBlockNumber", endBlockNumber)
 			}
 
-			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 i := startBlockNumber; i <= endBlockNumber; i++ {
+				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++
+					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()
 		}
 	}
 
@@ -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 e5df78d42f62..f3896db4b8fa 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 e28231d2fb9f..c3fe173fadc8 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 2c009c5b90f4..a9a4c816fbcc 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

From e50c789c77eb28d06815b77a45c225e85d745d0f Mon Sep 17 00:00:00 2001
From: Nguyen Sy Thanh Son <thanhson1085@gmail.com>
Date: Fri, 11 Jan 2019 04:58:10 +0000
Subject: [PATCH 2/7] move cache data to insert func

---
 consensus/posv/posv.go | 7 ++++---
 contracts/utils.go     | 2 +-
 core/blockchain.go     | 4 ++++
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go
index d30a4f2b32c2..893edca3e83a 100644
--- a/consensus/posv/posv.go
+++ b/consensus/posv/posv.go
@@ -877,7 +877,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state
 		}
 	}
 
-	_ = c.cacheData(header, 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))
@@ -1033,7 +1033,7 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea
 	return masternodes
 }
 
-func (c *Posv) cacheData(header *types.Header, 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() {
@@ -1054,6 +1054,7 @@ func (c *Posv) cacheData(header *types.Header, txs []*types.Transaction, receipt
 	}
 
 	c.BlockSigners.Add(header.Hash(), signTxs)
+	fmt.Println("Add cache BLockSigners", header.Hash().String(), len(signTxs), c.BlockSigners.Len())
 
 	return nil
 }
@@ -1071,7 +1072,7 @@ func (c *Posv) GetSignData(chain consensus.ChainReader, startBlockNumber uint64,
 				data[blkHash] = append(data[blkHash], from)
 			}
 		} else {
-			return nil, errors.New("Failed get blocksigners from cache")
+			return nil, errors.New("Failed get blocksigners from cache " + block.Hash().String() + " " + block.Number.String())
 		}
 	}
 	return data, nil
diff --git a/contracts/utils.go b/contracts/utils.go
index 078a0b69beba..f085c7b8f39f 100644
--- a/contracts/utils.go
+++ b/contracts/utils.go
@@ -353,7 +353,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign
 		} else {
 			data, err := c.GetSignData(chain, startBlockNumber, endBlockNumber)
 			if err != nil {
-				log.Crit("Fail to get signers from cache.", "endBlockNumber", startBlockNumber, "startBlockNumber", endBlockNumber)
+				log.Crit("Fail to get signers from cache.", "startBlockNumber", startBlockNumber, "endBlockNumber", endBlockNumber, "error", err)
 			}
 
 			for i := startBlockNumber; i <= endBlockNumber; i++ {
diff --git a/core/blockchain.go b/core/blockchain.go
index 4d6c2cc01187..5bd0a709be5f 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -506,6 +506,10 @@ func (bc *BlockChain) insert(block *types.Block) {
 	}
 	bc.currentBlock.Store(block)
 
+	// save cache BlockSigners
+	engine := bc.Engine().(*posv.Posv)
+	engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash()))
+
 	// If the block is better than our head or is on a different chain, force update heads
 	if updateHeads {
 		bc.hc.SetCurrentHeader(block.Header())

From 5e8df83303eaeb7987e16b6ce05e7958e4df3759 Mon Sep 17 00:00:00 2001
From: Nguyen Sy Thanh Son <thanhson1085@gmail.com>
Date: Fri, 11 Jan 2019 07:00:46 +0000
Subject: [PATCH 3/7] read signing data from blocks

---
 consensus/posv/posv.go |  19 +-------
 contracts/utils.go     | 100 ++++++++++++++++++++---------------------
 2 files changed, 52 insertions(+), 67 deletions(-)

diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go
index 893edca3e83a..fcf7d367faee 100644
--- a/consensus/posv/posv.go
+++ b/consensus/posv/posv.go
@@ -1059,23 +1059,8 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt
 	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 " + block.Hash().String() + " " + block.Number.String())
-		}
-	}
-	return data, nil
+func (c *Posv) GetDb() ethdb.Database {
+	return c.db
 }
 
 // Extract validators from byte array.
diff --git a/contracts/utils.go b/contracts/utils.go
index f085c7b8f39f..e554caa65940 100644
--- a/contracts/utils.go
+++ b/contracts/utils.go
@@ -317,71 +317,71 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign
 
 	if len(masternodes) > 0 {
 
-		if !c.EnableCache {
-			for i := startBlockNumber; i <= endBlockNumber; i++ {
-				block := chain.GetHeaderByNumber(i)
-				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
+		data := make(map[common.Hash][]common.Address)
+		for i := startBlockNumber; i <= chain.CurrentHeader().Number.Uint64(); i++ {
+			header := chain.GetHeaderByNumber(i)
+
+			if signData, ok := c.BlockSigners.Get(header.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)
 				}
-				// 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
-								}
+			} else {
+				log.Info("Failed get from cached", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
+				block := chain.GetBlock(header.Hash(), i)
+				txs := block.Transactions()
+				receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i)
+
+				for _, tx := range txs {
+					if tx.IsSigningTransaction() {
+						var b uint
+						for _, r := range receipts {
+							if r.TxHash == tx.Hash() {
+								b = r.Status
 								break
 							}
 						}
-					}
 
-					for addr := range addrSigners {
-						_, exist := signers[addr]
-						if exist {
-							signers[addr].Sign++
-						} else {
-							signers[addr] = &rewardLog{1, new(big.Int)}
+						if b == types.ReceiptStatusFailed {
+							continue
 						}
-						*totalSigner++
+
+						blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
+						from := *tx.From()
+						data[blkHash] = append(data[blkHash], from)
 					}
 				}
+
 			}
-		} else {
-			data, err := c.GetSignData(chain, startBlockNumber, endBlockNumber)
-			if err != nil {
-				log.Crit("Fail to get signers from cache.", "startBlockNumber", startBlockNumber, "endBlockNumber", endBlockNumber, "error", err)
-			}
+		}
 
-			for i := startBlockNumber; i <= endBlockNumber; i++ {
-				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 i := startBlockNumber; i <= endBlockNumber; i++ {
+			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++
+				for addr := range addrSigners {
+					_, exist := signers[addr]
+					if exist {
+						signers[addr].Sign++
+					} else {
+						signers[addr] = &rewardLog{1, new(big.Int)}
 					}
+					*totalSigner++
 				}
 			}
 		}

From f9ae05c5d5b78a067f163a291e2c51e11a4a26d6 Mon Sep 17 00:00:00 2001
From: Nguyen Sy Thanh Son <thanhson1085@gmail.com>
Date: Fri, 11 Jan 2019 07:42:30 +0000
Subject: [PATCH 4/7] cache all after 1 epoch

---
 consensus/posv/posv.go | 12 ++----------
 contracts/utils.go     |  9 ++++++---
 core/blockchain.go     |  4 ----
 eth/backend.go         |  4 +---
 4 files changed, 9 insertions(+), 20 deletions(-)

diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go
index fcf7d367faee..dd740ce6b584 100644
--- a/consensus/posv/posv.go
+++ b/consensus/posv/posv.go
@@ -225,7 +225,6 @@ type Posv struct {
 	signFn clique.SignerFn // Signer function to authorize hashes with
 	lock   sync.RWMutex    // Protects the signer fields
 
-	EnableCache   bool
 	BlockSigners  *lru.Cache
 	Votes         *lru.Cache
 	HookReward    func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{})
@@ -251,7 +250,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv {
 	return &Posv{
 		config:              &conf,
 		db:                  db,
-		EnableCache:         false,
 		BlockSigners:        BlockSigners,
 		recents:             recents,
 		signatures:          signatures,
@@ -856,12 +854,9 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state
 	number := header.Number.Uint64()
 	rCheckpoint := chain.Config().Posv.RewardCheckpoint
 
-	if c.HookReward != nil && number%rCheckpoint == 0 {
-		if !c.EnableCache && int(c.BlockSigners.Len()) >= int(rCheckpoint*3) {
-			log.Debug("EnableCache true c.BlockSigners.Len() ", "BlockSigners.Len", c.BlockSigners.Len())
-			c.EnableCache = true
-		}
+	_ = c.CacheData(header, txs, receipts)
 
+	if c.HookReward != nil && number%rCheckpoint == 0 {
 		err, rewards := c.HookReward(chain, state, header)
 		if err != nil {
 			return nil, err
@@ -877,8 +872,6 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state
 		}
 	}
 
-	// _ = c.cacheData(header, txs, receipts)
-
 	// the state remains as is and uncles are dropped
 	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
 	header.UncleHash = types.CalcUncleHash(nil)
@@ -1054,7 +1047,6 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt
 	}
 
 	c.BlockSigners.Add(header.Hash(), signTxs)
-	fmt.Println("Add cache BLockSigners", header.Hash().String(), len(signTxs), c.BlockSigners.Len())
 
 	return nil
 }
diff --git a/contracts/utils.go b/contracts/utils.go
index e554caa65940..9fb2203be366 100644
--- a/contracts/utils.go
+++ b/contracts/utils.go
@@ -306,7 +306,7 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte)
 }
 
 // Calculate reward for reward checkpoint.
-func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSignerAddr common.Address, number uint64, rCheckpoint uint64, client bind.ContractBackend, totalSigner *uint64) (map[common.Address]*rewardLog, error) {
+func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, number uint64, rCheckpoint uint64, totalSigner *uint64) (map[common.Address]*rewardLog, error) {
 	// Not reward for singer of genesis block and only calculate reward at checkpoint block.
 	prevCheckpoint := number - (rCheckpoint * 2)
 	startBlockNumber := prevCheckpoint + 1
@@ -318,7 +318,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign
 	if len(masternodes) > 0 {
 
 		data := make(map[common.Hash][]common.Address)
-		for i := startBlockNumber; i <= chain.CurrentHeader().Number.Uint64(); i++ {
+		for i := startBlockNumber; i <= prevCheckpoint+(rCheckpoint*2)-1; i++ {
 			header := chain.GetHeaderByNumber(i)
 
 			if signData, ok := c.BlockSigners.Get(header.Hash()); ok {
@@ -329,11 +329,12 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign
 					data[blkHash] = append(data[blkHash], from)
 				}
 			} else {
-				log.Info("Failed get from cached", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
+				log.Info("Failed get from cached", "hash", header.Hash().String(), "number", i)
 				block := chain.GetBlock(header.Hash(), i)
 				txs := block.Transactions()
 				receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i)
 
+				var signTxs []*types.Transaction
 				for _, tx := range txs {
 					if tx.IsSigningTransaction() {
 						var b uint
@@ -348,11 +349,13 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign
 							continue
 						}
 
+						signTxs = append(signTxs, tx)
 						blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
 						from := *tx.From()
 						data[blkHash] = append(data[blkHash], from)
 					}
 				}
+				c.BlockSigners.Add(header.Hash(), signTxs)
 
 			}
 		}
diff --git a/core/blockchain.go b/core/blockchain.go
index 5bd0a709be5f..4d6c2cc01187 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -506,10 +506,6 @@ func (bc *BlockChain) insert(block *types.Block) {
 	}
 	bc.currentBlock.Store(block)
 
-	// save cache BlockSigners
-	engine := bc.Engine().(*posv.Posv)
-	engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash()))
-
 	// If the block is better than our head or is on a different chain, force update heads
 	if updateHeads {
 		bc.hc.SetCurrentHeader(block.Header())
diff --git a/eth/backend.go b/eth/backend.go
index c3fe173fadc8..6fb12e08979e 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -300,14 +300,12 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 			rewards := make(map[string]interface{})
 			if number > 0 && number-rCheckpoint > 0 && foudationWalletAddr != (common.Address{}) {
 				start := time.Now()
-				// Get signers in blockSigner smartcontract.
-				addr := common.HexToAddress(common.BlockSigners)
 				// Get reward inflation.
 				chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().Posv.Reward), new(big.Int).SetUint64(params.Ether))
 				chainReward = rewardInflation(chainReward, number, common.BlocksPerYear)
 
 				totalSigner := new(uint64)
-				signers, err := contracts.GetRewardForCheckpoint(c, chain, addr, number, rCheckpoint, client, totalSigner)
+				signers, err := contracts.GetRewardForCheckpoint(c, chain, number, rCheckpoint, totalSigner)
 				log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
 				if err != nil {
 					log.Crit("Fail to get signers for reward checkpoint", "error", err)

From 46c96249bf3b9d8cb806762319f723cf7247c249 Mon Sep 17 00:00:00 2001
From: Nguyen Sy Thanh Son <thanhson1085@gmail.com>
Date: Fri, 11 Jan 2019 10:55:02 +0000
Subject: [PATCH 5/7] cache only blocksigners

---
 consensus/posv/posv.go |  1 -
 contracts/utils.go     | 32 +++++++++++++++-----------------
 eth/backend.go         |  2 +-
 3 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go
index dd740ce6b584..ef4b2ae1d0c6 100644
--- a/consensus/posv/posv.go
+++ b/consensus/posv/posv.go
@@ -226,7 +226,6 @@ type Posv struct {
 	lock   sync.RWMutex    // Protects the signer fields
 
 	BlockSigners  *lru.Cache
-	Votes         *lru.Cache
 	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)
diff --git a/contracts/utils.go b/contracts/utils.go
index 9fb2203be366..bdfde9828c31 100644
--- a/contracts/utils.go
+++ b/contracts/utils.go
@@ -329,31 +329,29 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, number ui
 					data[blkHash] = append(data[blkHash], from)
 				}
 			} else {
-				log.Info("Failed get from cached", "hash", header.Hash().String(), "number", i)
+				log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i)
 				block := chain.GetBlock(header.Hash(), i)
 				txs := block.Transactions()
 				receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i)
 
 				var signTxs []*types.Transaction
 				for _, tx := range txs {
-					if tx.IsSigningTransaction() {
-						var b uint
-						for _, r := range receipts {
-							if r.TxHash == tx.Hash() {
-								b = r.Status
-								break
-							}
-						}
-
-						if b == types.ReceiptStatusFailed {
-							continue
+					var b uint
+					for _, r := range receipts {
+						if r.TxHash == tx.Hash() {
+							b = r.Status
+							break
 						}
+					}
 
-						signTxs = append(signTxs, tx)
-						blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
-						from := *tx.From()
-						data[blkHash] = append(data[blkHash], from)
+					if b == types.ReceiptStatusFailed {
+						continue
 					}
+
+					signTxs = append(signTxs, tx)
+					blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
+					from := *tx.From()
+					data[blkHash] = append(data[blkHash], from)
 				}
 				c.BlockSigners.Add(header.Hash(), signTxs)
 
@@ -433,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) {
+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)
 	if err != nil {
 		return err, nil
diff --git a/eth/backend.go b/eth/backend.go
index 6fb12e08979e..e990093a89b0 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -324,7 +324,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 				voterResults := make(map[common.Address]interface{})
 				if len(signers) > 0 {
 					for signer, calcReward := range rewardSigners {
-						err, rewards := contracts.CalculateRewardForHolders(c, foudationWalletAddr, validator, state, signer, calcReward)
+						err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward)
 						if err != nil {
 							log.Crit("Fail to calculate reward for holders.", "error", err)
 						}

From cd81c5c8b6d7d38dc13117260b7a390a25595a63 Mon Sep 17 00:00:00 2001
From: Nguyen Sy Thanh Son <thanhson1085@gmail.com>
Date: Fri, 11 Jan 2019 15:32:48 +0000
Subject: [PATCH 6/7] move cache to insert func

---
 consensus/posv/posv.go | 3 ++-
 core/blockchain.go     | 4 ++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go
index ef4b2ae1d0c6..2dccf1cd3709 100644
--- a/consensus/posv/posv.go
+++ b/consensus/posv/posv.go
@@ -853,7 +853,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state
 	number := header.Number.Uint64()
 	rCheckpoint := chain.Config().Posv.RewardCheckpoint
 
-	_ = c.CacheData(header, txs, receipts)
+	// _ = c.CacheData(header, txs, receipts)
 
 	if c.HookReward != nil && number%rCheckpoint == 0 {
 		err, rewards := c.HookReward(chain, state, header)
@@ -1045,6 +1045,7 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt
 		}
 	}
 
+	log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs))
 	c.BlockSigners.Add(header.Hash(), signTxs)
 
 	return nil
diff --git a/core/blockchain.go b/core/blockchain.go
index 4d6c2cc01187..5bd0a709be5f 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -506,6 +506,10 @@ func (bc *BlockChain) insert(block *types.Block) {
 	}
 	bc.currentBlock.Store(block)
 
+	// save cache BlockSigners
+	engine := bc.Engine().(*posv.Posv)
+	engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash()))
+
 	// If the block is better than our head or is on a different chain, force update heads
 	if updateHeads {
 		bc.hc.SetCurrentHeader(block.Header())

From 381864d869a2c53f9f2d01ab810db4a757692e32 Mon Sep 17 00:00:00 2001
From: Nguyen Sy Thanh Son <thanhson1085@gmail.com>
Date: Fri, 11 Jan 2019 17:14:12 +0000
Subject: [PATCH 7/7] verify signing tx

---
 common/types.go           |  1 +
 contracts/utils.go        | 28 +++++++++++++++-------------
 core/types/transaction.go | 17 ++++++++++++++++-
 3 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/common/types.go b/common/types.go
index ad06240675af..6a7be73c98d9 100644
--- a/common/types.go
+++ b/common/types.go
@@ -39,6 +39,7 @@ const (
 	UnvoteMethod        = "0x02aa9be2"
 	ProposeMethod       = "0x01267951"
 	ResignMethod        = "0xae6e43f5"
+	SignMethod          = "0xe341eaa4"
 )
 
 var (
diff --git a/contracts/utils.go b/contracts/utils.go
index bdfde9828c31..d48207e2003a 100644
--- a/contracts/utils.go
+++ b/contracts/utils.go
@@ -336,22 +336,24 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, number ui
 
 				var signTxs []*types.Transaction
 				for _, tx := range txs {
-					var b uint
-					for _, r := range receipts {
-						if r.TxHash == tx.Hash() {
-							b = r.Status
-							break
+					if tx.IsSigningTransaction() {
+						var b uint
+						for _, r := range receipts {
+							if r.TxHash == tx.Hash() {
+								b = r.Status
+								break
+							}
 						}
-					}
 
-					if b == types.ReceiptStatusFailed {
-						continue
-					}
+						if b == types.ReceiptStatusFailed {
+							continue
+						}
 
-					signTxs = append(signTxs, tx)
-					blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
-					from := *tx.From()
-					data[blkHash] = append(data[blkHash], from)
+						signTxs = append(signTxs, tx)
+						blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
+						from := *tx.From()
+						data[blkHash] = append(data[blkHash], from)
+					}
 				}
 				c.BlockSigners.Add(header.Hash(), signTxs)
 
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 9bc42013b0a4..339e3562f52f 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -291,7 +291,22 @@ func (tx *Transaction) IsSigningTransaction() bool {
 	if tx.To() == nil {
 		return false
 	}
-	return tx.To().String() == common.BlockSigners
+
+	if tx.To().String() != common.BlockSigners {
+		return false
+	}
+
+	method := common.ToHex(tx.Data()[0:4])
+
+	if method != common.SignMethod {
+		return false
+	}
+
+	if len(tx.Data()) != (32*2 + 4) {
+		return false
+	}
+
+	return true
 }
 
 func (tx *Transaction) IsVotingTransaction() (bool, *common.Address) {