OSDN Git Service

add consensus engine
[bytom/vapor.git] / mining / consensus / dpos / dpos.go
1 package dpos
2
3 import (
4         "errors"
5         "fmt"
6         "math/big"
7         "sync"
8         "time"
9
10         "github.com/go-loom/types"
11         lru "github.com/hashicorp/golang-lru"
12         log "github.com/sirupsen/logrus"
13         "github.com/vapor/common"
14         "github.com/vapor/config"
15         "github.com/vapor/protocol"
16         "github.com/vapor/protocol/bc"
17 )
18
19 const (
20         inMemorySnapshots  = 128             // Number of recent vote snapshots to keep in memory
21         inMemorySignatures = 4096            // Number of recent block signatures to keep in memory
22         secondsPerYear     = 365 * 24 * 3600 // Number of seconds for one year
23         checkpointInterval = 360             // About N hours if config.period is N
24         module             = "dpos"
25 )
26
27 //delegated-proof-of-stake protocol constants.
28 var (
29         SignerBlockReward                = big.NewInt(5e+18) // Block reward in wei for successfully mining a block first year
30         defaultEpochLength               = uint64(3000000)   // Default number of blocks after which vote's period of validity
31         defaultBlockPeriod               = uint64(3)         // Default minimum difference between two consecutive block's timestamps
32         defaultMaxSignerCount            = uint64(21)        //
33         defaultMinVoterBalance           = new(big.Int).Mul(big.NewInt(10000), big.NewInt(1e+18))
34         extraVanity                      = 32            // Fixed number of extra-data prefix bytes reserved for signer vanity
35         extraSeal                        = 65            // Fixed number of extra-data suffix bytes reserved for signer seal
36         defaultDifficulty                = big.NewInt(1) // Default difficulty
37         defaultLoopCntRecalculateSigners = uint64(10)    // Default loop count to recreate signers from top tally
38         minerRewardPerThousand           = uint64(618)   // Default reward for miner in each block from block reward (618/1000)
39         candidateNeedPD                  = false         // is new candidate need Proposal & Declare process
40 )
41
42 var (
43         // errUnknownBlock is returned when the list of signers is requested for a block
44         // that is not part of the local blockchain.
45         errUnknownBlock = errors.New("unknown block")
46
47         // errMissingVanity is returned if a block's extra-data section is shorter than
48         // 32 bytes, which is required to store the signer vanity.
49         errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
50
51         // errMissingSignature is returned if a block's extra-data section doesn't seem
52         // to contain a 65 byte secp256k1 signature.
53         errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
54
55         // errInvalidMixDigest is returned if a block's mix digest is non-zero.
56         errInvalidMixDigest = errors.New("non-zero mix digest")
57
58         // errInvalidUncleHash is returned if a block contains an non-empty uncle list.
59         errInvalidUncleHash = errors.New("non empty uncle hash")
60
61         // ErrInvalidTimestamp is returned if the timestamp of a block is lower than
62         // the previous block's timestamp + the minimum block period.
63         ErrInvalidTimestamp = errors.New("invalid timestamp")
64
65         // errInvalidVotingChain is returned if an authorization list is attempted to
66         // be modified via out-of-range or non-contiguous headers.
67         errInvalidVotingChain = errors.New("invalid voting chain")
68
69         // errUnauthorized is returned if a header is signed by a non-authorized entity.
70         errUnauthorized = errors.New("unauthorized")
71
72         // errPunishedMissing is returned if a header calculate punished signer is wrong.
73         errPunishedMissing = errors.New("punished signer missing")
74
75         // errWaitTransactions is returned if an empty block is attempted to be sealed
76         // on an instant chain (0 second period). It's important to refuse these as the
77         // block reward is zero, so an empty block just bloats the chain... fast.
78         errWaitTransactions = errors.New("waiting for transactions")
79
80         // errUnclesNotAllowed is returned if uncles exists
81         errUnclesNotAllowed = errors.New("uncles not allowed")
82
83         // errCreateSignerQueueNotAllowed is returned if called in (block number + 1) % maxSignerCount != 0
84         errCreateSignerQueueNotAllowed = errors.New("create signer queue not allowed")
85
86         // errInvalidSignerQueue is returned if verify SignerQueue fail
87         errInvalidSignerQueue = errors.New("invalid signer queue")
88
89         // errSignerQueueEmpty is returned if no signer when calculate
90         errSignerQueueEmpty = errors.New("signer queue is empty")
91 )
92
93 type Dpos struct {
94         config     *config.DposConfig // Consensus engine configuration parameters
95         store      protocol.Store     // Database to store and retrieve snapshot checkpoints
96         recents    *lru.ARCCache      // Snapshots for recent block to speed up reorgs
97         signatures *lru.ARCCache      // Signatures of recent blocks to speed up mining
98         signer     common.Address     // Ethereum address of the signing key
99         signFn     SignerFn           // Signer function to authorize hashes with
100         signTxFn   SignTxFn           // Sign transaction function to sign tx
101         lock       sync.RWMutex       // Protects the signer fields
102         lcsc       uint64             // Last confirmed side chain
103 }
104
105 // SignerFn is a signer callback function to request a hash to be signed by a backing account.
106 type SignerFn func(common.Address, []byte) ([]byte, error)
107
108 // SignTxFn is a signTx
109 type SignTxFn func(common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)
110
111 //
112 func ecrecover(header *types.BlockHeader, sigcache *lru.ARCCache) (common.Address, error) {
113         return nil, nil
114 }
115
116 func sigHash(header *types.BlockHeader) (hash bc.Hash) {
117         return bc.Hash{}
118 }
119
120 //
121 func New(config *config.DposConfig, store protocol.Store) *Dpos {
122         conf := *config
123         if conf.Epoch == 0 {
124                 conf.Epoch = defaultEpochLength
125         }
126         if conf.Period == 0 {
127                 conf.Period = defaultBlockPeriod
128         }
129         if conf.MaxSignerCount == 0 {
130                 conf.MaxSignerCount = defaultMaxSignerCount
131         }
132         if conf.MinVoterBalance.Uint64() == 0 {
133                 conf.MinVoterBalance = defaultMinVoterBalance
134         }
135
136         // Allocate the snapshot caches and create the engine
137         recents, _ := lru.NewARC(inMemorySnapshots)
138         signatures, _ := lru.NewARC(inMemorySignatures)
139         return &Dpos{
140                 config:     &conf,
141                 store:      store,
142                 recents:    recents,
143                 signatures: signatures,
144         }
145 }
146
147 // 从BLockHeader中获取到地址
148 func (d *Dpos) Author(header *types.BlockHeader) (common.Address, error) {
149         return ecrecover(header, d.signatures)
150 }
151
152 // Prepare implements consensus.Engine, preparing all the consensus fields of the header for running the transactions on top.
153 func (d *Dpos) Prepare(c *protocol.Chain, header *bc.BlockHeader) error {
154         if d.config.GenesisTimestamp < uint64(time.Now().Unix()) {
155                 return nil
156         }
157
158         if header.Height == 1 {
159                 for {
160                         delay := time.Unix(int64(d.config.GenesisTimestamp-2), 0).Sub(time.Now())
161                         if delay <= time.Duration(0) {
162                                 log.WithFields(log.Fields{"module": module, "time": time.Now()}).Info("Ready for seal block")
163                                 break
164                         } else if delay > time.Duration(d.config.Period)*time.Second {
165                                 delay = time.Duration(d.config.Period) * time.Second
166                         }
167                         log.WithFields(log.Fields{"module": module, "delay": time.Duration(time.Unix(int64(d.config.GenesisTimestamp-2), 0).Sub(time.Now()))}).Info("Waiting for seal block")
168                         select {
169                         case <-time.After(delay):
170                                 continue
171                         }
172                 }
173         }
174         return nil
175 }
176
177 func (d *Dpos) Finalize(c *protocol.Chain, header *bc.BlockHeader, txs []*types.Transaction) (*bc.Block, error) {
178         height := c.BestBlockHeight()
179         fmt.Println(height)
180         parent, err := c.GetHeaderByHeight(height - 1)
181         if parent == nil {
182                 return nil, err
183         }
184         //header.Timestamp
185         t := new(big.Int).Add(new(big.Int).SetUint64(parent.Timestamp), new(big.Int).SetUint64(d.config.Period))
186         header.Timestamp = t.Uint64()
187
188         if header.Timestamp < uint64(time.Now().Unix()) {
189                 header.Timestamp = uint64(time.Now().Unix())
190         }
191         
192
193         return nil, nil
194 }
195
196 func (d *Dpos) Seal() {
197
198 }