github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/qbft/engine/engine.go (about) 1 package qbftengine 2 3 import ( 4 "bytes" 5 "math/big" 6 "time" 7 8 "github.com/kisexp/xdchain/common" 9 "github.com/kisexp/xdchain/consensus" 10 "github.com/kisexp/xdchain/consensus/istanbul" 11 istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common" 12 "github.com/kisexp/xdchain/consensus/istanbul/validator" 13 "github.com/kisexp/xdchain/core/state" 14 "github.com/kisexp/xdchain/core/types" 15 "github.com/kisexp/xdchain/rlp" 16 "github.com/kisexp/xdchain/trie" 17 "golang.org/x/crypto/sha3" 18 ) 19 20 var ( 21 nilUncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW. 22 ) 23 24 type SignerFn func(data []byte) ([]byte, error) 25 26 type Engine struct { 27 cfg *istanbul.Config 28 29 signer common.Address // Ethereum address of the signing key 30 sign SignerFn // Signer function to authorize hashes with 31 } 32 33 func NewEngine(cfg *istanbul.Config, signer common.Address, sign SignerFn) *Engine { 34 return &Engine{ 35 cfg: cfg, 36 signer: signer, 37 sign: sign, 38 } 39 } 40 41 func (e *Engine) Author(header *types.Header) (common.Address, error) { 42 return header.Coinbase, nil 43 } 44 45 func (e *Engine) CommitHeader(header *types.Header, seals [][]byte, round *big.Int) error { 46 return ApplyHeaderQBFTExtra( 47 header, 48 writeCommittedSeals(seals), 49 writeRoundNumber(round), 50 ) 51 } 52 53 // writeCommittedSeals writes the extra-data field of a block header with given committed seals. 54 func writeCommittedSeals(committedSeals [][]byte) ApplyQBFTExtra { 55 return func(qbftExtra *types.QBFTExtra) error { 56 if len(committedSeals) == 0 { 57 return istanbulcommon.ErrInvalidCommittedSeals 58 } 59 60 for _, seal := range committedSeals { 61 if len(seal) != types.IstanbulExtraSeal { 62 return istanbulcommon.ErrInvalidCommittedSeals 63 } 64 } 65 66 qbftExtra.CommittedSeal = make([][]byte, len(committedSeals)) 67 copy(qbftExtra.CommittedSeal, committedSeals) 68 69 return nil 70 } 71 } 72 73 // writeRoundNumber writes the extra-data field of a block header with given round. 74 func writeRoundNumber(round *big.Int) ApplyQBFTExtra { 75 return func(qbftExtra *types.QBFTExtra) error { 76 qbftExtra.Round = uint32(round.Uint64()) 77 return nil 78 } 79 } 80 81 func (e *Engine) VerifyBlockProposal(chain consensus.ChainHeaderReader, block *types.Block, validators istanbul.ValidatorSet) (time.Duration, error) { 82 // check block body 83 txnHash := types.DeriveSha(block.Transactions(), new(trie.Trie)) 84 if txnHash != block.Header().TxHash { 85 return 0, istanbulcommon.ErrMismatchTxhashes 86 } 87 88 uncleHash := types.CalcUncleHash(block.Uncles()) 89 if uncleHash != nilUncleHash { 90 return 0, istanbulcommon.ErrInvalidUncleHash 91 } 92 93 // verify the header of proposed block 94 err := e.VerifyHeader(chain, block.Header(), nil, validators) 95 if err == nil || err == istanbulcommon.ErrEmptyCommittedSeals { 96 // ignore errEmptyCommittedSeals error because we don't have the committed seals yet 97 return 0, nil 98 } else if err == consensus.ErrFutureBlock { 99 return time.Until(time.Unix(int64(block.Header().Time), 0)), consensus.ErrFutureBlock 100 } 101 102 return 0, err 103 } 104 105 func (e *Engine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 106 return e.verifyHeader(chain, header, parents, validators) 107 } 108 109 // verifyHeader checks whether a header conforms to the consensus rules.The 110 // caller may optionally pass in a batch of parents (ascending order) to avoid 111 // looking those up from the database. This is useful for concurrently verifying 112 // a batch of new headers. 113 func (e *Engine) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 114 if header.Number == nil { 115 return istanbulcommon.ErrUnknownBlock 116 } 117 118 // Don't waste time checking blocks from the future (adjusting for allowed threshold) 119 adjustedTimeNow := time.Now().Add(time.Duration(e.cfg.AllowedFutureBlockTime) * time.Second).Unix() 120 if header.Time > uint64(adjustedTimeNow) { 121 return consensus.ErrFutureBlock 122 } 123 124 if _, err := types.ExtractQBFTExtra(header); err != nil { 125 return istanbulcommon.ErrInvalidExtraDataFormat 126 } 127 128 // Ensure that the mix digest is zero as we don't have fork protection currently 129 if header.MixDigest != types.IstanbulDigest { 130 return istanbulcommon.ErrInvalidMixDigest 131 } 132 133 // Ensure that the block doesn't contain any uncles which are meaningless in Istanbul 134 if header.UncleHash != nilUncleHash { 135 return istanbulcommon.ErrInvalidUncleHash 136 } 137 138 // Ensure that the block's difficulty is meaningful (may not be correct at this point) 139 if header.Difficulty == nil || header.Difficulty.Cmp(istanbulcommon.DefaultDifficulty) != 0 { 140 return istanbulcommon.ErrInvalidDifficulty 141 } 142 143 return e.verifyCascadingFields(chain, header, validators, parents) 144 } 145 146 func (e *Engine) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool, validators istanbul.ValidatorSet) (chan<- struct{}, <-chan error) { 147 abort := make(chan struct{}) 148 results := make(chan error, len(headers)) 149 go func() { 150 errored := false 151 for i, header := range headers { 152 var err error 153 if errored { 154 err = consensus.ErrUnknownAncestor 155 } else { 156 err = e.verifyHeader(chain, header, headers[:i], validators) 157 } 158 159 if err != nil { 160 errored = true 161 } 162 163 select { 164 case <-abort: 165 return 166 case results <- err: 167 } 168 } 169 }() 170 return abort, results 171 } 172 173 // verifyCascadingFields verifies all the header fields that are not standalone, 174 // rather depend on a batch of previous headers. The caller may optionally pass 175 // in a batch of parents (ascending order) to avoid looking those up from the 176 // database. This is useful for concurrently verifying a batch of new headers. 177 func (e *Engine) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet, parents []*types.Header) error { 178 // The genesis block is the always valid dead-end 179 number := header.Number.Uint64() 180 if number == 0 { 181 return nil 182 } 183 184 // Check parent 185 var parent *types.Header 186 if len(parents) > 0 { 187 parent = parents[len(parents)-1] 188 } else { 189 parent = chain.GetHeader(header.ParentHash, number-1) 190 } 191 192 // Ensure that the block's parent has right number and hash 193 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 194 return consensus.ErrUnknownAncestor 195 } 196 197 // Ensure that the block's timestamp isn't too close to it's parent 198 if parent.Time+e.cfg.BlockPeriod > header.Time { 199 return istanbulcommon.ErrInvalidTimestamp 200 } 201 202 // Verify signer 203 if err := e.verifySigner(chain, header, parents, validators); err != nil { 204 return err 205 } 206 207 return e.verifyCommittedSeals(chain, header, parents, validators) 208 } 209 210 func (e *Engine) verifySigner(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 211 // Verifying the genesis block is not supported 212 number := header.Number.Uint64() 213 if number == 0 { 214 return istanbulcommon.ErrUnknownBlock 215 } 216 217 // Resolve the authorization key and check against signers 218 signer, err := e.Author(header) 219 if err != nil { 220 return err 221 } 222 223 // Signer should be in the validator set of previous block's extraData. 224 if _, v := validators.GetByAddress(signer); v == nil { 225 return istanbulcommon.ErrUnauthorized 226 } 227 228 return nil 229 } 230 231 // verifyCommittedSeals checks whether every committed seal is signed by one of the parent's validators 232 func (e *Engine) verifyCommittedSeals(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 233 number := header.Number.Uint64() 234 235 if number == 0 { 236 // We don't need to verify committed seals in the genesis block 237 return nil 238 } 239 240 extra, err := types.ExtractQBFTExtra(header) 241 if err != nil { 242 return err 243 } 244 committedSeal := extra.CommittedSeal 245 246 // The length of Committed seals should be larger than 0 247 if len(committedSeal) == 0 { 248 return istanbulcommon.ErrEmptyCommittedSeals 249 } 250 251 validatorsCpy := validators.Copy() 252 253 // Check whether the committed seals are generated by validators 254 validSeal := 0 255 committers, err := e.Signers(header) 256 if err != nil { 257 return err 258 } 259 260 for _, addr := range committers { 261 if validatorsCpy.RemoveValidator(addr) { 262 validSeal++ 263 continue 264 } 265 return istanbulcommon.ErrInvalidCommittedSeals 266 } 267 268 // The length of validSeal should be larger than number of faulty node + 1 269 if validSeal <= validators.F() { 270 return istanbulcommon.ErrInvalidCommittedSeals 271 } 272 273 return nil 274 } 275 276 // VerifyUncles verifies that the given block's uncles conform to the consensus 277 // rules of a given engine. 278 func (e *Engine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 279 if len(block.Uncles()) > 0 { 280 return istanbulcommon.ErrInvalidUncleHash 281 } 282 return nil 283 } 284 285 // VerifySeal checks whether the crypto seal on a header is valid according to 286 // the consensus rules of the given engine. 287 func (e *Engine) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet) error { 288 // get parent header and ensure the signer is in parent's validator set 289 number := header.Number.Uint64() 290 if number == 0 { 291 return istanbulcommon.ErrUnknownBlock 292 } 293 294 // ensure that the difficulty equals to istanbulcommon.DefaultDifficulty 295 if header.Difficulty.Cmp(istanbulcommon.DefaultDifficulty) != 0 { 296 return istanbulcommon.ErrInvalidDifficulty 297 } 298 299 return e.verifySigner(chain, header, nil, validators) 300 } 301 302 func (e *Engine) Prepare(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet) error { 303 header.Coinbase = common.Address{} 304 header.Nonce = istanbulcommon.EmptyBlockNonce 305 header.MixDigest = types.IstanbulDigest 306 307 // copy the parent extra data as the header extra data 308 number := header.Number.Uint64() 309 310 parent := chain.GetHeader(header.ParentHash, number-1) 311 if parent == nil { 312 return consensus.ErrUnknownAncestor 313 } 314 315 // use the same difficulty for all blocks 316 header.Difficulty = istanbulcommon.DefaultDifficulty 317 318 // set header's timestamp 319 header.Time = parent.Time + e.cfg.BlockPeriod 320 if header.Time < uint64(time.Now().Unix()) { 321 header.Time = uint64(time.Now().Unix()) 322 } 323 324 // add validators in snapshot to extraData's validators section 325 return ApplyHeaderQBFTExtra( 326 header, 327 WriteValidators(validator.SortedAddresses(validators.List())), 328 ) 329 } 330 331 func WriteValidators(validators []common.Address) ApplyQBFTExtra { 332 return func(qbftExtra *types.QBFTExtra) error { 333 qbftExtra.Validators = validators 334 return nil 335 } 336 } 337 338 // Finalize runs any post-transaction state modifications (e.g. block rewards) 339 // and assembles the final block. 340 // 341 // Note, the block header and state database might be updated to reflect any 342 // consensus rules that happen at finalization (e.g. block rewards). 343 func (e *Engine) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { 344 // No block rewards in Istanbul, so the state remains as is and uncles are dropped 345 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 346 header.UncleHash = nilUncleHash 347 } 348 349 // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, 350 // nor block rewards given, and returns the final block. 351 func (e *Engine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { 352 /// No block rewards in Istanbul, so the state remains as is and uncles are dropped 353 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 354 header.UncleHash = nilUncleHash 355 356 // Assemble and return the final block for sealing 357 return types.NewBlock(header, txs, nil, receipts, new(trie.Trie)), nil 358 } 359 360 // Seal generates a new block for the given input block with the local miner's 361 // seal place on top. 362 func (e *Engine) Seal(chain consensus.ChainHeaderReader, block *types.Block, validators istanbul.ValidatorSet) (*types.Block, error) { 363 if _, v := validators.GetByAddress(e.signer); v == nil { 364 return block, istanbulcommon.ErrUnauthorized 365 } 366 367 header := block.Header() 368 parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 369 if parent == nil { 370 return block, consensus.ErrUnknownAncestor 371 } 372 373 // Set Coinbase 374 header.Coinbase = e.signer 375 376 return block.WithSeal(header), nil 377 } 378 379 func (e *Engine) SealHash(header *types.Header) common.Hash { 380 header.Coinbase = e.signer 381 return sigHash(header) 382 } 383 384 func (e *Engine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { 385 return new(big.Int) 386 } 387 388 func (e *Engine) Validators(header *types.Header) ([]common.Address, error) { 389 extra, err := types.ExtractQBFTExtra(header) 390 if err != nil { 391 return nil, err 392 } 393 394 return extra.Validators, nil 395 } 396 397 func (e *Engine) Signers(header *types.Header) ([]common.Address, error) { 398 extra, err := types.ExtractQBFTExtra(header) 399 if err != nil { 400 return []common.Address{}, err 401 } 402 committedSeal := extra.CommittedSeal 403 proposalSeal := PrepareCommittedSeal(header, extra.Round) 404 405 var addrs []common.Address 406 // 1. Get committed seals from current header 407 for _, seal := range committedSeal { 408 // 2. Get the original address by seal and parent block hash 409 addr, err := istanbul.GetSignatureAddressNoHashing(proposalSeal, seal) 410 if err != nil { 411 return nil, istanbulcommon.ErrInvalidSignature 412 } 413 addrs = append(addrs, addr) 414 } 415 416 return addrs, nil 417 } 418 419 func (e *Engine) Address() common.Address { 420 return e.signer 421 } 422 423 // FIXME: Need to update this for Istanbul 424 // sigHash returns the hash which is used as input for the Istanbul 425 // signing. It is the hash of the entire header apart from the 65 byte signature 426 // contained at the end of the extra data. 427 // 428 // Note, the method requires the extra data to be at least 65 bytes, otherwise it 429 // panics. This is done to avoid accidentally using both forms (signature present 430 // or not), which could be abused to produce different hashes for the same header. 431 func sigHash(header *types.Header) (hash common.Hash) { 432 hasher := sha3.NewLegacyKeccak256() 433 rlp.Encode(hasher, types.QBFTFilteredHeader(header)) 434 hasher.Sum(hash[:0]) 435 return hash 436 } 437 438 // PrepareCommittedSeal returns a committed seal for the given hash 439 func PrepareCommittedSeal(header *types.Header, round uint32) []byte { 440 h := types.CopyHeader(header) 441 return h.QBFTHashWithRoundNumber(round).Bytes() 442 } 443 444 func (e *Engine) WriteVote(header *types.Header, candidate common.Address, authorize bool) error { 445 return ApplyHeaderQBFTExtra( 446 header, 447 WriteVote(candidate, authorize), 448 ) 449 } 450 451 func WriteVote(candidate common.Address, authorize bool) ApplyQBFTExtra { 452 return func(qbftExtra *types.QBFTExtra) error { 453 voteType := types.QBFTDropVote 454 if authorize { 455 voteType = types.QBFTAuthVote 456 } 457 458 vote := &types.ValidatorVote{RecipientAddress: candidate, VoteType: voteType} 459 qbftExtra.Vote = vote 460 return nil 461 } 462 } 463 464 func (e *Engine) ReadVote(header *types.Header) (candidate common.Address, authorize bool, err error) { 465 qbftExtra, err := getExtra(header) 466 if err != nil { 467 return common.Address{}, false, err 468 } 469 470 var vote *types.ValidatorVote 471 if qbftExtra.Vote == nil { 472 vote = &types.ValidatorVote{RecipientAddress: common.Address{}, VoteType: types.QBFTDropVote} 473 } else { 474 vote = qbftExtra.Vote 475 } 476 477 // Tally up the new vote from the validator 478 switch { 479 case vote.VoteType == types.QBFTAuthVote: 480 authorize = true 481 case vote.VoteType == types.QBFTDropVote: 482 authorize = false 483 default: 484 return common.Address{}, false, istanbulcommon.ErrInvalidVote 485 } 486 487 return vote.RecipientAddress, authorize, nil 488 } 489 490 func getExtra(header *types.Header) (*types.QBFTExtra, error) { 491 if len(header.Extra) < types.IstanbulExtraVanity { 492 // In this scenario, the header extradata only contains client specific information, hence create a new qbftExtra and set vanity 493 vanity := append(header.Extra, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity-len(header.Extra))...) 494 return &types.QBFTExtra{ 495 VanityData: vanity, 496 Validators: []common.Address{}, 497 CommittedSeal: [][]byte{}, 498 Round: 0, 499 Vote: nil, 500 }, nil 501 } 502 503 // This is the case when Extra has already been set 504 return types.ExtractQBFTExtra(header) 505 } 506 507 func setExtra(h *types.Header, qbftExtra *types.QBFTExtra) error { 508 payload, err := rlp.EncodeToBytes(qbftExtra) 509 if err != nil { 510 return err 511 } 512 513 h.Extra = payload 514 return nil 515 }