Skip to content

Commit c20e84f

Browse files
authored
Merge pull request ethereum#384 from thanhson1085/master
Implement Cache to speed up checkpoint
2 parents 6ce2611 + e9a3e7b commit c20e84f

File tree

7 files changed

+249
-49
lines changed

7 files changed

+249
-49
lines changed

common/types.go

+9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ const (
3535
RandomizeSMC = "0x0000000000000000000000000000000000000090"
3636
FoudationAddr = "0x0000000000000000000000000000000000000068"
3737
TeamAddr = "0x0000000000000000000000000000000000000099"
38+
VoteMethod = "0x6dd7d8ea"
39+
UnvoteMethod = "0x02aa9be2"
40+
ProposeMethod = "0x01267951"
41+
ResignMethod = "0xae6e43f5"
3842
)
3943

4044
var (
@@ -45,6 +49,11 @@ var (
4549
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
4650
type Hash [HashLength]byte
4751

52+
type Vote struct {
53+
Masternode Address
54+
Voter Address
55+
}
56+
4857
func BytesToHash(b []byte) Hash {
4958
var h Hash
5059
h.SetBytes(b)

consensus/posv/posv.go

+62-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ import (
4848
)
4949

5050
const (
51-
inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
52-
M2ByteLength = 4
51+
inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
52+
blockSignersCacheLimit = 36000
53+
votingCacheLimit = 1500000
54+
M2ByteLength = 4
5355
)
5456

5557
type Masternode struct {
@@ -224,6 +226,9 @@ type Posv struct {
224226
signFn clique.SignerFn // Signer function to authorize hashes with
225227
lock sync.RWMutex // Protects the signer fields
226228

229+
EnableCache bool
230+
BlockSigners *lru.Cache
231+
Votes *lru.Cache
227232
HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{})
228233
HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error)
229234
HookValidator func(header *types.Header, signers []common.Address) ([]byte, error)
@@ -239,13 +244,18 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv {
239244
conf.Epoch = epochLength
240245
}
241246
// Allocate the snapshot caches and create the engine
247+
BlockSigners, _ := lru.New(blockSignersCacheLimit)
248+
Votes, _ := lru.New(votingCacheLimit)
242249
recents, _ := lru.NewARC(inmemorySnapshots)
243250
signatures, _ := lru.NewARC(inmemorySnapshots)
244251
validatorSignatures, _ := lru.NewARC(inmemorySnapshots)
245252
verifiedHeaders, _ := lru.NewARC(inmemorySnapshots)
246253
return &Posv{
247254
config: &conf,
248255
db: db,
256+
EnableCache: false,
257+
BlockSigners: BlockSigners,
258+
Votes: Votes,
249259
recents: recents,
250260
signatures: signatures,
251261
verifiedHeaders: verifiedHeaders,
@@ -850,6 +860,11 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state
850860
rCheckpoint := chain.Config().Posv.RewardCheckpoint
851861

852862
if c.HookReward != nil && number%rCheckpoint == 0 {
863+
if !c.EnableCache && int(c.BlockSigners.Len()) >= int(rCheckpoint*3) {
864+
log.Debug("EnableCache true c.BlockSigners.Len() ", "BlockSigners.Len", c.BlockSigners.Len())
865+
c.EnableCache = true
866+
}
867+
853868
err, rewards := c.HookReward(chain, state, header)
854869
if err != nil {
855870
return nil, err
@@ -865,6 +880,8 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state
865880
}
866881
}
867882

883+
_ = c.cacheData(txs, receipts)
884+
868885
// the state remains as is and uncles are dropped
869886
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
870887
header.UncleHash = types.CalcUncleHash(nil)
@@ -1019,6 +1036,49 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea
10191036
return masternodes
10201037
}
10211038

1039+
func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) error {
1040+
for _, tx := range txs {
1041+
if tx.IsSigningTransaction() {
1042+
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
1043+
from := *tx.From()
1044+
1045+
var b uint
1046+
for _, r := range receipts {
1047+
if r.TxHash == tx.Hash() {
1048+
b = r.Status
1049+
break
1050+
}
1051+
}
1052+
1053+
if b == types.ReceiptStatusFailed {
1054+
continue
1055+
}
1056+
1057+
var lAddr []common.Address
1058+
if cached, ok := c.BlockSigners.Get(blkHash); ok {
1059+
lAddr = cached.([]common.Address)
1060+
lAddr = append(lAddr, from)
1061+
} else {
1062+
lAddr = []common.Address{from}
1063+
}
1064+
c.BlockSigners.Add(blkHash, lAddr)
1065+
} else {
1066+
1067+
b, addr := tx.IsVotingTransaction()
1068+
if b && addr != nil {
1069+
var vote common.Vote
1070+
vote.Masternode = *addr
1071+
vote.Voter = *tx.From()
1072+
1073+
log.Debug("Remove from Votes cache ", "Masternode", vote.Masternode.String(), "Voter", vote.Voter.String())
1074+
c.Votes.Remove(vote)
1075+
}
1076+
}
1077+
}
1078+
1079+
return nil
1080+
}
1081+
10221082
// Extract validators from byte array.
10231083
func RemovePenaltiesFromBlock(chain consensus.ChainReader, masternodes []common.Address, epochNumber uint64) []common.Address {
10241084
if epochNumber <= 0 {

contracts/utils.go

+113-41
Original file line numberDiff line numberDiff line change
@@ -199,20 +199,23 @@ func BuildTxOpeningRandomize(nonce uint64, randomizeAddr common.Address, randomi
199199
}
200200

201201
// Get signers signed for blockNumber from blockSigner contract.
202-
func GetSignersFromContract(addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) {
202+
func GetSignersFromContract(c *posv.Posv, addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) {
203203
blockSigner, err := contract.NewBlockSigner(addrBlockSigner, client)
204204
if err != nil {
205205
log.Error("Fail get instance of blockSigner", "error", err)
206206
return nil, err
207207
}
208-
opts := new(bind.CallOpts)
209-
addrs, err := blockSigner.GetSigners(opts, blockHash)
210-
if err != nil {
211-
log.Error("Fail get block signers", "error", err)
212-
return nil, err
208+
if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || !c.EnableCache {
209+
opts := new(bind.CallOpts)
210+
addrs, err := blockSigner.GetSigners(opts, blockHash)
211+
if err != nil {
212+
log.Error("Fail get block signers", "error", err)
213+
return nil, err
214+
}
215+
return addrs, nil
216+
} else {
217+
return caddrs.([]common.Address), nil
213218
}
214-
215-
return addrs, nil
216219
}
217220

218221
// Get random from randomize contract.
@@ -307,7 +310,7 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte)
307310
}
308311

309312
// Calculate reward for reward checkpoint.
310-
func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common.Address, number uint64, rCheckpoint uint64, client bind.ContractBackend, totalSigner *uint64) (map[common.Address]*rewardLog, error) {
313+
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) {
311314
// Not reward for singer of genesis block and only calculate reward at checkpoint block.
312315
prevCheckpoint := number - (rCheckpoint * 2)
313316
startBlockNumber := prevCheckpoint + 1
@@ -317,37 +320,89 @@ func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common.
317320
masternodes := posv.GetMasternodesFromCheckpointHeader(prevHeaderCheckpoint)
318321

319322
if len(masternodes) > 0 {
320-
for i := startBlockNumber; i <= endBlockNumber; i++ {
321-
block := chain.GetHeaderByNumber(i)
322-
addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash())
323-
if err != nil {
324-
log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i)
325-
return nil, err
326-
}
327-
// Filter duplicate address.
328-
if len(addrs) > 0 {
329-
addrSigners := make(map[common.Address]bool)
330-
for _, masternode := range masternodes {
331-
for _, addr := range addrs {
332-
if addr == masternode {
333-
if _, ok := addrSigners[addr]; !ok {
334-
addrSigners[addr] = true
323+
324+
if !c.EnableCache {
325+
for i := startBlockNumber; i <= endBlockNumber; i++ {
326+
block := chain.GetHeaderByNumber(i)
327+
addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash())
328+
if err != nil {
329+
log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i)
330+
return nil, err
331+
}
332+
// Filter duplicate address.
333+
if len(addrs) > 0 {
334+
addrSigners := make(map[common.Address]bool)
335+
for _, masternode := range masternodes {
336+
for _, addr := range addrs {
337+
if addr == masternode {
338+
if _, ok := addrSigners[addr]; !ok {
339+
addrSigners[addr] = true
340+
}
341+
break
335342
}
336-
break
337343
}
338344
}
345+
346+
for addr := range addrSigners {
347+
_, exist := signers[addr]
348+
if exist {
349+
signers[addr].Sign++
350+
} else {
351+
signers[addr] = &rewardLog{1, new(big.Int)}
352+
}
353+
*totalSigner++
354+
}
339355
}
356+
}
357+
} else {
358+
var wg sync.WaitGroup
359+
squeue := make(chan []common.Address, 1)
360+
wg.Add(int(rCheckpoint))
361+
362+
for i := startBlockNumber; i <= endBlockNumber; i++ {
363+
go func(i uint64) {
364+
block := chain.GetHeaderByNumber(i)
365+
addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash())
366+
if err != nil {
367+
log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i)
368+
}
369+
squeue <- addrs
370+
}(i)
371+
}
340372

341-
for addr := range addrSigners {
342-
_, exist := signers[addr]
343-
if exist {
344-
signers[addr].Sign++
345-
} else {
346-
signers[addr] = &rewardLog{1, new(big.Int)}
373+
fsigner := func() {
374+
for addrs := range squeue {
375+
// Filter duplicate address.
376+
if len(addrs) > 0 {
377+
addrSigners := make(map[common.Address]bool)
378+
for _, masternode := range masternodes {
379+
for _, addr := range addrs {
380+
if addr == masternode {
381+
if _, ok := addrSigners[addr]; !ok {
382+
addrSigners[addr] = true
383+
}
384+
break
385+
}
386+
}
387+
}
388+
389+
for addr := range addrSigners {
390+
_, exist := signers[addr]
391+
if exist {
392+
signers[addr].Sign++
393+
} else {
394+
signers[addr] = &rewardLog{1, new(big.Int)}
395+
}
396+
*totalSigner++
397+
}
347398
}
348-
*totalSigner++
399+
wg.Done()
349400
}
350401
}
402+
403+
go fsigner()
404+
405+
wg.Wait()
351406
}
352407
}
353408

@@ -381,7 +436,6 @@ func CalculateRewardForSigner(chainReward *big.Int, signers map[common.Address]*
381436
return resultSigners, nil
382437
}
383438

384-
// Get candidate owner by address.
385439
func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, signerAddr common.Address) common.Address {
386440
owner := signerAddr
387441
opts := new(bind.CallOpts)
@@ -395,8 +449,8 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign
395449
}
396450

397451
// Calculate reward for holders.
398-
func CalculateRewardForHolders(foudationWalletAddr common.Address, validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) {
399-
rewards, err := GetRewardBalancesRate(foudationWalletAddr, signer, calcReward, validator)
452+
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) {
453+
rewards, err := GetRewardBalancesRate(c, foudationWalletAddr, signer, calcReward, validator)
400454
if err != nil {
401455
return err, nil
402456
}
@@ -409,7 +463,7 @@ func CalculateRewardForHolders(foudationWalletAddr common.Address, validator *co
409463
}
410464

411465
// Get reward balance rates for master node, founder and holders.
412-
func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) {
466+
func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) {
413467
owner := GetCandidatesOwnerBySigner(validator, masterAddr)
414468
balances := make(map[common.Address]*big.Int)
415469
rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardMasterPercent))
@@ -419,7 +473,7 @@ func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common
419473
opts := new(bind.CallOpts)
420474
voters, err := validator.GetVoters(opts, masterAddr)
421475
if err != nil {
422-
log.Error("Fail to get voters", "error", err)
476+
log.Crit("Fail to get voters", "error", err)
423477
return nil, err
424478
}
425479

@@ -430,10 +484,28 @@ func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common
430484
// Get voters capacities.
431485
voterCaps := make(map[common.Address]*big.Int)
432486
for _, voteAddr := range voters {
433-
voterCap, err := validator.GetVoterCap(opts, masterAddr, voteAddr)
434-
if err != nil {
435-
log.Error("Fail to get vote capacity", "error", err)
436-
return nil, err
487+
var vote common.Vote
488+
var voterCap *big.Int
489+
490+
vote.Masternode = masterAddr
491+
vote.Voter = voteAddr
492+
493+
if c != nil {
494+
if vCap, ok := c.Votes.Get(vote); ok {
495+
voterCap = vCap.(*big.Int)
496+
} else {
497+
voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr)
498+
if err != nil {
499+
log.Crit("Fail to get vote capacity", "error", err)
500+
}
501+
log.Debug("Add to Votes cache ", "vote.Masternode", vote.Masternode.String(), "vote.Voter", vote.Voter.String(), "voterCap", voterCap.String())
502+
c.Votes.Add(vote, voterCap)
503+
}
504+
} else {
505+
voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr)
506+
if err != nil {
507+
log.Crit("Fail to get vote capacity", "error", err)
508+
}
437509
}
438510

439511
totalCap.Add(totalCap, voterCap)

contracts/validator/validator_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func TestRewardBalance(t *testing.T) {
144144

145145
foundationAddr := common.HexToAddress(common.FoudationAddr)
146146
totalReward := new(big.Int).SetInt64(15 * 1000)
147-
rewards, err := contracts.GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator)
147+
rewards, err := contracts.GetRewardBalancesRate(nil, foundationAddr, acc3Addr, totalReward, baseValidator)
148148
if err != nil {
149149
t.Error("Fail to get reward balances rate.", err)
150150
}

0 commit comments

Comments
 (0)