aboutsummaryrefslogtreecommitdiffstats
path: root/core/leader-selector.go
blob: a6b9c8e794fded62f8794c64adfc69366caa79e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Copyright 2018 The dexon-consensus-core Authors
// This file is part of the dexon-consensus-core library.
//
// The dexon-consensus-core library is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// The dexon-consensus-core library is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the dexon-consensus-core library. If not, see
// <http://www.gnu.org/licenses/>.

package core

import (
    "fmt"
    "math/big"

    "github.com/dexon-foundation/dexon-consensus-core/common"
    "github.com/dexon-foundation/dexon-consensus-core/core/crypto"
    "github.com/dexon-foundation/dexon-consensus-core/core/types"
)

// Errors for leader module.
var (
    ErrIncorrectCRSSignature = fmt.Errorf("incorrect CRS signature")
)

// Some constant value.
var (
    maxHash *big.Int
    one     *big.Rat
)

func init() {
    hash := make([]byte, common.HashLength)
    for i := range hash {
        hash[i] = 0xff
    }
    maxHash = big.NewInt(0).SetBytes(hash)
    one = big.NewRat(1, 1)
}

type leaderSelector struct {
    hashCRS      common.Hash
    numCRS       *big.Int
    minCRSBlock  *big.Int
    minBlockHash common.Hash
}

func newGenesisLeaderSelector(
    crs []byte) *leaderSelector {
    hash := crypto.Keccak256Hash(crs)
    return newLeaderSelector(hash)
}

func newLeaderSelector(
    crs common.Hash) *leaderSelector {
    numCRS := big.NewInt(0)
    numCRS.SetBytes(crs[:])
    return &leaderSelector{
        numCRS:      numCRS,
        hashCRS:     crs,
        minCRSBlock: maxHash,
    }
}

func (l *leaderSelector) distance(sig crypto.Signature) *big.Int {
    hash := crypto.Keccak256Hash(sig.Signature[:])
    num := big.NewInt(0)
    num.SetBytes(hash[:])
    num.Abs(num.Sub(l.numCRS, num))
    return num
}

func (l *leaderSelector) probability(sig crypto.Signature) float64 {
    dis := l.distance(sig)
    prob := big.NewRat(1, 1).SetFrac(dis, maxHash)
    p, _ := prob.Sub(one, prob).Float64()
    return p
}

func (l *leaderSelector) restart() {
    l.minCRSBlock = maxHash
    l.minBlockHash = common.Hash{}
}

func (l *leaderSelector) leaderBlockHash() common.Hash {
    return l.minBlockHash
}

func (l *leaderSelector) prepareBlock(
    block *types.Block, prv crypto.PrivateKey) (err error) {
    block.CRSSignature, err = prv.Sign(hashCRS(block, l.hashCRS))
    return
}

func (l *leaderSelector) processBlock(block *types.Block) error {
    ok, err := verifyCRSSignature(block, l.hashCRS)
    if err != nil {
        return err
    }
    if !ok {
        return ErrIncorrectCRSSignature
    }
    dist := l.distance(block.CRSSignature)
    if l.minCRSBlock.Cmp(dist) == 1 {
        l.minCRSBlock = dist
        l.minBlockHash = block.Hash
    }
    return nil
}