cache votercap

This commit is contained in:
Nguyen Sy Thanh Son 2019-01-03 09:57:50 +00:00
parent 752ac2b426
commit 5a51506652
5 changed files with 146 additions and 56 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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,6 +315,40 @@ 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(c, blockSignerAddr, client, block.Hash())
if err != nil {
log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i)
return nil, err
}
// 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++
}
}
}
} else {
var wg sync.WaitGroup
squeue := make(chan []common.Address, 1)
wg.Add(900)
@ -365,6 +399,8 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign
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

View file

@ -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 {

View file

@ -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)
}