github.com/Elemental-core/elementalcore@v0.0.0-20191206075037-63891242267a/consensus/dpos/dpos.go (about) 1 package dpos 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 lru "github.com/hashicorp/golang-lru" 9 "github.com/Elemental-core/elementalcore/accounts" 10 "github.com/Elemental-core/elementalcore/common" 11 "github.com/Elemental-core/elementalcore/consensus" 12 "github.com/Elemental-core/elementalcore/consensus/misc" 13 "github.com/Elemental-core/elementalcore/core/state" 14 "github.com/Elemental-core/elementalcore/core/types" 15 "github.com/Elemental-core/elementalcore/crypto" 16 "github.com/Elemental-core/elementalcore/crypto/sha3" 17 "github.com/Elemental-core/elementalcore/ethdb" 18 "github.com/Elemental-core/elementalcore/log" 19 "github.com/Elemental-core/elementalcore/params" 20 "github.com/Elemental-core/elementalcore/rlp" 21 "github.com/Elemental-core/elementalcore/rpc" 22 "github.com/Elemental-core/elementalcore/trie" 23 "math/big" 24 "sync" 25 "time" 26 ) 27 28 const ( 29 extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity 30 extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal 31 inmemorySignatures = 4096 // Number of recent block signatures to keep in memory 32 33 blockInterval = int64(5) 34 epochInterval = int64(5) 35 maxValidatorSize = 3 36 safeSize = maxValidatorSize*2/3 + 1 37 consensusSize = maxValidatorSize*2/3 + 1 38 ) 39 40 var ( 41 big0 = big.NewInt(0) 42 big8 = big.NewInt(8) 43 big32 = big.NewInt(32) 44 45 frontierBlockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block 46 byzantiumBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium 47 48 timeOfFirstBlock = int64(0) 49 50 confirmedBlockHead = []byte("confirmed-block-head") 51 ) 52 53 var ( 54 // errUnknownBlock is returned when the list of signers is requested for a block 55 // that is not part of the local blockchain. 56 errUnknownBlock = errors.New("unknown block") 57 // errMissingVanity is returned if a block's extra-data section is shorter than 58 // 32 bytes, which is required to store the signer vanity. 59 errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing") 60 // errMissingSignature is returned if a block's extra-data section doesn't seem 61 // to contain a 65 byte secp256k1 signature. 62 errMissingSignature = errors.New("extra-data 65 byte suffix signature missing") 63 // errInvalidMixDigest is returned if a block's mix digest is non-zero. 64 errInvalidMixDigest = errors.New("non-zero mix digest") 65 // errInvalidUncleHash is returned if a block contains an non-empty uncle list. 66 errInvalidUncleHash = errors.New("non empty uncle hash") 67 errInvalidDifficulty = errors.New("invalid difficulty") 68 69 // ErrInvalidTimestamp is returned if the timestamp of a block is lower than 70 // the previous block's timestamp + the minimum block period. 71 ErrInvalidTimestamp = errors.New("invalid timestamp") 72 ErrWaitForPrevBlock = errors.New("wait for last block arrived") 73 ErrMintFutureBlock = errors.New("mint the future block") 74 ErrMismatchSignerAndValidator = errors.New("mismatch block signer and validator") 75 ErrInvalidBlockValidator = errors.New("invalid block validator") 76 ErrInvalidMintBlockTime = errors.New("invalid time to mint the block") 77 ErrNilBlockHeader = errors.New("nil block header returned") 78 ) 79 var ( 80 uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW. 81 ) 82 83 type Dpos struct { 84 config *params.DposConfig // Consensus engine configuration parameters 85 db ethdb.Database // Database to store and retrieve snapshot checkpoints 86 87 signer common.Address 88 signFn SignerFn 89 signatures *lru.ARCCache // Signatures of recent blocks to speed up mining 90 confirmedBlockHeader *types.Header 91 92 mu sync.RWMutex 93 stop chan bool 94 } 95 96 type SignerFn func(accounts.Account, []byte) ([]byte, error) 97 98 // NOTE: sigHash was copy from clique 99 // sigHash returns the hash which is used as input for the proof-of-authority 100 // signing. It is the hash of the entire header apart from the 65 byte signature 101 // contained at the end of the extra data. 102 // 103 // Note, the method requires the extra data to be at least 65 bytes, otherwise it 104 // panics. This is done to avoid accidentally using both forms (signature present 105 // or not), which could be abused to produce different hashes for the same header. 106 func sigHash(header *types.Header) (hash common.Hash) { 107 hasher := sha3.NewKeccak256() 108 109 rlp.Encode(hasher, []interface{}{ 110 header.ParentHash, 111 header.UncleHash, 112 header.Validator, 113 header.Coinbase, 114 header.Root, 115 header.TxHash, 116 header.ReceiptHash, 117 header.Bloom, 118 header.Difficulty, 119 header.Number, 120 header.GasLimit, 121 header.GasUsed, 122 header.Time, 123 header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short 124 header.MixDigest, 125 header.Nonce, 126 header.DposContext.Root(), 127 }) 128 hasher.Sum(hash[:0]) 129 return hash 130 } 131 132 func New(config *params.DposConfig, db ethdb.Database) *Dpos { 133 signatures, _ := lru.NewARC(inmemorySignatures) 134 return &Dpos{ 135 config: config, 136 db: db, 137 signatures: signatures, 138 } 139 } 140 141 func (d *Dpos) Author(header *types.Header) (common.Address, error) { 142 return header.Validator, nil 143 } 144 145 func (d *Dpos) Coinbase(header *types.Header) (common.Address, error) { 146 return header.Coinbase, nil 147 } 148 149 func (d *Dpos) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { 150 return d.verifyHeader(chain, header, nil) 151 } 152 153 func (d *Dpos) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 154 if header.Number == nil { 155 return errUnknownBlock 156 } 157 number := header.Number.Uint64() 158 // Unnecssary to verify the block from feature 159 if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 { 160 return consensus.ErrFutureBlock 161 } 162 // Check that the extra-data contains both the vanity and signature 163 if len(header.Extra) < extraVanity { 164 return errMissingVanity 165 } 166 if len(header.Extra) < extraVanity+extraSeal { 167 return errMissingSignature 168 } 169 // Ensure that the mix digest is zero as we don't have fork protection currently 170 if header.MixDigest != (common.Hash{}) { 171 return errInvalidMixDigest 172 } 173 // Difficulty always 1 174 if header.Difficulty.Uint64() != 1 { 175 return errInvalidDifficulty 176 } 177 // Ensure that the block doesn't contain any uncles which are meaningless in DPoS 178 if header.UncleHash != uncleHash { 179 return errInvalidUncleHash 180 } 181 // If all checks passed, validate any special fields for hard forks 182 if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { 183 return err 184 } 185 186 var parent *types.Header 187 if len(parents) > 0 { 188 parent = parents[len(parents)-1] 189 } else { 190 parent = chain.GetHeader(header.ParentHash, number-1) 191 } 192 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 193 return consensus.ErrUnknownAncestor 194 } 195 if parent.Time.Uint64()+uint64(blockInterval) > header.Time.Uint64() { 196 return ErrInvalidTimestamp 197 } 198 return nil 199 } 200 201 func (d *Dpos) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 202 abort := make(chan struct{}) 203 results := make(chan error, len(headers)) 204 205 go func() { 206 for i, header := range headers { 207 err := d.verifyHeader(chain, header, headers[:i]) 208 select { 209 case <-abort: 210 return 211 case results <- err: 212 } 213 } 214 }() 215 return abort, results 216 } 217 218 // VerifyUncles implements consensus.Engine, always returning an error for any 219 // uncles as this consensus mechanism doesn't permit uncles. 220 func (d *Dpos) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 221 if len(block.Uncles()) > 0 { 222 return errors.New("uncles not allowed") 223 } 224 return nil 225 } 226 227 // VerifySeal implements consensus.Engine, checking whether the signature contained 228 // in the header satisfies the consensus protocol requirements. 229 func (d *Dpos) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 230 return d.verifySeal(chain, header, nil) 231 } 232 233 func (d *Dpos) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 234 // Verifying the genesis block is not supported 235 number := header.Number.Uint64() 236 if number == 0 { 237 return errUnknownBlock 238 } 239 var parent *types.Header 240 if len(parents) > 0 { 241 parent = parents[len(parents)-1] 242 } else { 243 parent = chain.GetHeader(header.ParentHash, number-1) 244 } 245 246 return d.updateConfirmedBlockHeader(chain) 247 } 248 249 func (d *Dpos) verifyBlockSigner(validator common.Address, header *types.Header) error { 250 signer, err := ecrecover(header, d.signatures) 251 if err != nil { 252 return err 253 } 254 if bytes.Compare(signer.Bytes(), validator.Bytes()) != 0 { 255 return ErrInvalidBlockValidator 256 } 257 if bytes.Compare(signer.Bytes(), header.Validator.Bytes()) != 0 { 258 return ErrMismatchSignerAndValidator 259 } 260 return nil 261 } 262 263 func (d *Dpos) updateConfirmedBlockHeader(chain consensus.ChainReader) error { 264 265 } 266 267 func (d *Dpos) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 268 uncles []*types.Header, receipts []*types.Receipt, dposContext *types.DposContext) (*types.Block, error) { 269 270 271 header.DposContext = dposContext.ToProto() 272 return types.NewBlock(header, txs, uncles, receipts), nil 273 } 274 275 func (d *Dpos) checkDeadline(lastBlock *types.Block, now int64) error { 276 prevSlot := PrevSlot(now) 277 nextSlot := NextSlot(now) 278 if lastBlock.Time().Int64() >= nextSlot { 279 return ErrMintFutureBlock 280 } 281 // last block was arrived, or time's up 282 if lastBlock.Time().Int64() == prevSlot || nextSlot-now <= 1 { 283 return nil 284 } 285 return ErrWaitForPrevBlock 286 } 287 288 func (d *Dpos) CheckValidator(lastBlock *types.Block, now int64) error { 289 if err := d.checkDeadline(lastBlock, now); err != nil { 290 return err 291 } 292 dposContext, err := types.NewDposContextFromProto(d.db, lastBlock.Header().DposContext) 293 if err != nil { 294 return idator 295 } 296 return nil 297 } 298 299 // Seal generates a new block for the given input block with the local miner's 300 // seal place on top. 301 func (d *Dpos) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { 302 header := block.Header() 303 number := header.Number.Uint64() 304 // Sealing the genesis block is not supported 305 if number == 0 { 306 return nil, errUnknownBlock 307 } 308 309 return block.WithSeal(header), nil 310 } 311 312 func (d *Dpos) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 313 return big.NewInt(1) 314 } 315 316 func (d *Dpos) APIs(chain consensus.ChainReader) []rpc.API { 317 return []rpc.API{{ 318 Namespace: "dpos", 319 Version: "1.0", 320 Service: &API{chain: chain, dpos: d}, 321 Public: true, 322 }} 323 } 324 325 func (d *Dpos) Authorize(signer common.Address, signFn SignerFn) { 326 d.mu.Lock() 327 d.signer = signer 328 d.signFn = signFn 329 d.mu.Unlock() 330 } 331 332 // ecrecover extracts the Ethereum account address from a signed header. 333 func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) { 334 // If the signature's already cached, return that 335 hash := header.Hash() 336 if address, known := sigcache.Get(hash); known { 337 return address.(common.Address), nil 338 } 339 340 var signer common.Address 341 copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) 342 sigcache.Add(hash, signer) 343 return signer, nil 344 } 345 346 func PrevSlot(now int64) int64 { 347 return int64((now-1)/blockInterval) * blockInterval 348 } 349 350 func NextSlot(now int64) int64 { 351 return int64((now+blockInterval-1)/blockInterval) * blockInterval 352 } 353 354 // update counts in MintCntTrie for the miner of newBlock 355 func updateMintCnt(parentBlockTime, currentBlockTime int64, validator common.Address, dposContext *types.DposContext) { 356 currentMintCntTrie := dposContext.MintCntTrie() 357 currentEpoch := parentBlockTime / epochInterval 358 currentEpochBytes := make([]byte, 8) 359 binary.BigEndian.PutUint64(currentEpochBytes, uint64(currentEpoch)) 360 361 362 363 newCntBytes := make([]byte, 8) 364 newEpochBytes := make([]byte, 8) 365 binary.BigEndian.PutUint64(newEpochBytes, uint64(newEpoch)) 366 binary.BigEndian.PutUint64(newCntBytes, uint64(cnt)) 367 dposContext.MintCntTrie().TryUpdate(append(newEpochBytes, validator.Bytes()...), newCntBytes) 368 } 369