From d3ad6c39f27da5b7c98c28c5449c6a6358a1400d Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Wed, 2 Jan 2019 12:50:05 +0000 Subject: [PATCH] try use cache for blocksigners --- consensus/posv/posv.go | 20 ++++++++++++++++++-- contracts/utils.go | 26 +++++++++++++++++++++++--- eth/backend.go | 3 ++- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index a6f0613954..09f97207b6 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -48,8 +48,9 @@ import ( ) const ( - inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory - M2ByteLength = 4 + inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory + blockSignersCacheLimit = 1800 + M2ByteLength = 4 ) type Masternode struct { @@ -224,6 +225,7 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields + BlockSigners *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) @@ -239,6 +241,7 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { conf.Epoch = epochLength } // Allocate the snapshot caches and create the engine + BlockSigners, _ := lru.NewARC(blockSignersCacheLimit) recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySnapshots) validatorSignatures, _ := lru.NewARC(inmemorySnapshots) @@ -246,6 +249,7 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { return &Posv{ config: &conf, db: db, + BlockSigners: BlockSigners, recents: recents, signatures: signatures, verifiedHeaders: verifiedHeaders, @@ -254,6 +258,10 @@ 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) { @@ -849,6 +857,14 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint + var lAddr []common.Address + for _, tx := range txs { + if tx.IsSigningTransaction() { + lAddr = append(lAddr, *tx.From()) + } + } + c.BlockSigners.Add(header.Hash(), lAddr) + if c.HookReward != nil && number%rCheckpoint == 0 { err, rewards := c.HookReward(chain, state, header) if err != nil { diff --git a/contracts/utils.go b/contracts/utils.go index 3f8350f187..c24f90c3b7 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -208,10 +208,29 @@ func GetSignersFromContract(addrBlockSigner common.Address, client bind.Contract log.Error("Fail get block signers", "error", err) return nil, err } - return addrs, nil } +func GetSignersFromContract2(c *posv.Posv, 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 + } + opts := new(bind.CallOpts) + if caddrs, ok := c.GetBlockSigners().Get(blockHash); !ok { + 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 + } + return nil, nil +} + // Get random from randomize contract. func GetRandomizeFromContract(client bind.ContractBackend, addrMasternode common.Address) (int64, error) { randomize, err := randomizeContract.NewTomoRandomize(common.HexToAddress(common.RandomizeSMC), client) @@ -300,7 +319,7 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) } // Calculate reward for reward checkpoint. -func GetRewardForCheckpoint(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, blockSignerAddr common.Address, number uint64, rCheckpoint uint64, client bind.ContractBackend, 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 +337,8 @@ func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common. for i := startBlockNumber; i <= endBlockNumber; i++ { go func(i uint64) { block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) + addrs, err := GetSignersFromContract2(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 diff --git a/eth/backend.go b/eth/backend.go index 6c2022e19c..2f0b5fcd3c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -307,7 +307,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { chainReward = rewardInflation(chainReward, number, common.BlocksPerYear) totalSigner := new(uint64) - signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) + signers, err := contracts.GetRewardForCheckpoint(c, chain, addr, number, rCheckpoint, client, totalSigner) + // signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) fmt.Println("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)