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"
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
27 //delegated-proof-of-stake protocol constants.
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
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")
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")
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")
55 // errInvalidMixDigest is returned if a block's mix digest is non-zero.
56 errInvalidMixDigest = errors.New("non-zero mix digest")
58 // errInvalidUncleHash is returned if a block contains an non-empty uncle list.
59 errInvalidUncleHash = errors.New("non empty uncle hash")
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")
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")
69 // errUnauthorized is returned if a header is signed by a non-authorized entity.
70 errUnauthorized = errors.New("unauthorized")
72 // errPunishedMissing is returned if a header calculate punished signer is wrong.
73 errPunishedMissing = errors.New("punished signer missing")
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")
80 // errUnclesNotAllowed is returned if uncles exists
81 errUnclesNotAllowed = errors.New("uncles not allowed")
83 // errCreateSignerQueueNotAllowed is returned if called in (block number + 1) % maxSignerCount != 0
84 errCreateSignerQueueNotAllowed = errors.New("create signer queue not allowed")
86 // errInvalidSignerQueue is returned if verify SignerQueue fail
87 errInvalidSignerQueue = errors.New("invalid signer queue")
89 // errSignerQueueEmpty is returned if no signer when calculate
90 errSignerQueueEmpty = errors.New("signer queue is empty")
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
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)
108 // SignTxFn is a signTx
109 type SignTxFn func(common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)
112 func ecrecover(header *types.BlockHeader, sigcache *lru.ARCCache) (common.Address, error) {
116 func sigHash(header *types.BlockHeader) (hash bc.Hash) {
121 func New(config *config.DposConfig, store protocol.Store) *Dpos {
124 conf.Epoch = defaultEpochLength
126 if conf.Period == 0 {
127 conf.Period = defaultBlockPeriod
129 if conf.MaxSignerCount == 0 {
130 conf.MaxSignerCount = defaultMaxSignerCount
132 if conf.MinVoterBalance.Uint64() == 0 {
133 conf.MinVoterBalance = defaultMinVoterBalance
136 // Allocate the snapshot caches and create the engine
137 recents, _ := lru.NewARC(inMemorySnapshots)
138 signatures, _ := lru.NewARC(inMemorySignatures)
143 signatures: signatures,
147 // 从BLockHeader中获取到地址
148 func (d *Dpos) Author(header *types.BlockHeader) (common.Address, error) {
149 return ecrecover(header, d.signatures)
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()) {
158 if header.Height == 1 {
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")
164 } else if delay > time.Duration(d.config.Period)*time.Second {
165 delay = time.Duration(d.config.Period) * time.Second
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")
169 case <-time.After(delay):
177 func (d *Dpos) Finalize(c *protocol.Chain, header *bc.BlockHeader, txs []*types.Transaction) (*bc.Block, error) {
178 height := c.BestBlockHeight()
180 parent, err := c.GetHeaderByHeight(height - 1)
185 t := new(big.Int).Add(new(big.Int).SetUint64(parent.Timestamp), new(big.Int).SetUint64(d.config.Period))
186 header.Timestamp = t.Uint64()
188 if header.Timestamp < uint64(time.Now().Unix()) {
189 header.Timestamp = uint64(time.Now().Unix())
196 func (d *Dpos) Seal() {