github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/bft/backend/engine.go (about) 1 package backend 2 3 import ( 4 "bytes" 5 "errors" 6 "math/big" 7 "math/rand" 8 "time" 9 10 lru "github.com/hashicorp/golang-lru" 11 "github.com/quickchainproject/quickchain/common" 12 "github.com/quickchainproject/quickchain/common/hexutil" 13 "github.com/quickchainproject/quickchain/consensus" 14 "github.com/quickchainproject/quickchain/consensus/bft" 15 bftCore "github.com/quickchainproject/quickchain/consensus/bft/core" 16 "github.com/quickchainproject/quickchain/consensus/bft/validator" 17 "github.com/quickchainproject/quickchain/core/state" 18 "github.com/quickchainproject/quickchain/core/types" 19 "github.com/quickchainproject/quickchain/crypto/sha3" 20 "github.com/quickchainproject/quickchain/log" 21 "github.com/quickchainproject/quickchain/rlp" 22 "github.com/quickchainproject/quickchain/rpc" 23 ) 24 25 const ( 26 checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database 27 inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory 28 inmemoryPeers = 40 29 inmemoryMessages = 1024 30 ) 31 32 var ( 33 // errInvalidProposal is returned when a prposal is malformed. 34 errInvalidProposal = errors.New("invalid proposal") 35 // errInvalidSignature is returned when given signature is not signed by given 36 // address. 37 errInvalidSignature = errors.New("invalid signature") 38 // errUnknownBlock is returned when the list of validators is requested for a block 39 // that is not part of the local blockchain. 40 errUnknownBlock = errors.New("unknown block") 41 // errUnauthorized is returned if a header is signed by a non authorized entity. 42 errUnauthorized = errors.New("unauthorized") 43 // errInvalidDifficulty is returned if the difficulty of a block is not 1 44 errInvalidDifficulty = errors.New("invalid difficulty") 45 // errInvalidExtraDataFormat is returned when the extra data format is incorrect 46 errInvalidExtraDataFormat = errors.New("invalid extra data format") 47 // errInvalidMixDigest is returned if a block's mix digest is not BFT digest. 48 errInvalidMixDigest = errors.New("invalid BFT mix digest") 49 // errInvalidNonce is returned if a block's nonce is invalid 50 errInvalidNonce = errors.New("invalid nonce") 51 // errInvalidUncleHash is returned if a block contains an non-empty uncle list. 52 errInvalidUncleHash = errors.New("non empty uncle hash") 53 // errInconsistentValidatorSet is returned if the validator set is inconsistent 54 errInconsistentValidatorSet = errors.New("non empty uncle hash") 55 // errInvalidTimestamp is returned if the timestamp of a block is lower than the previous block's timestamp + the minimum block period. 56 errInvalidTimestamp = errors.New("invalid timestamp") 57 // errInvalidVotingChain is returned if an authorization list is attempted to 58 // be modified via out-of-range or non-contiguous headers. 59 errInvalidVotingChain = errors.New("invalid voting chain") 60 // errInvalidVote is returned if a nonce value is something else that the two 61 // allowed constants of 0x00..0 or 0xff..f. 62 errInvalidVote = errors.New("vote nonce not 0x00..0 or 0xff..f") 63 // errInvalidCommittedSeals is returned if the committed seal is not signed by any of parent validators. 64 errInvalidCommittedSeals = errors.New("invalid committed seals") 65 // errEmptyCommittedSeals is returned if the field of committed seals is zero. 66 errEmptyCommittedSeals = errors.New("zero committed seals") 67 // errMismatchTxhashes is returned if the TxHash in header is mismatch. 68 errMismatchTxhashes = errors.New("mismatch transcations hashes") 69 ) 70 var ( 71 defaultDifficulty = big.NewInt(1) 72 nilUncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW. 73 emptyNonce = types.BlockNonce{} 74 now = time.Now 75 76 nonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new validator 77 nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a validator. 78 79 inmemoryAddresses = 20 // Number of recent addresses from ecrecover 80 recentAddresses, _ = lru.NewARC(inmemoryAddresses) 81 ) 82 83 // Author retrieves the Ethereum address of the account that minted the given 84 // block, which may be different from the header's coinbase if a consensus 85 // engine is based on signatures. 86 func (sb *backend) Author(header *types.Header) (common.Address, error) { 87 return ecrecover(header) 88 } 89 90 // VerifyHeader checks whether a header conforms to the consensus rules of a 91 // given engine. Verifying the seal may be done optionally here, or explicitly 92 // via the VerifySeal method. 93 func (sb *backend) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { 94 return sb.verifyHeader(chain, header, nil) 95 } 96 97 // verifyHeader checks whether a header conforms to the consensus rules.The 98 // caller may optionally pass in a batch of parents (ascending order) to avoid 99 // looking those up from the database. This is useful for concurrently verifying 100 // a batch of new headers. 101 func (sb *backend) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 102 if header.Number == nil { 103 return errUnknownBlock 104 } 105 106 // Don't waste time checking blocks from the future 107 if header.Time.Cmp(big.NewInt(now().Unix())) > 0 { 108 return consensus.ErrFutureBlock 109 } 110 111 // Ensure that the extra data format is satisfied 112 if _, err := types.ExtractBFTExtra(header); err != nil { 113 return errInvalidExtraDataFormat 114 } 115 116 // Ensure that the coinbase is valid 117 if header.Nonce != (emptyNonce) && !bytes.Equal(header.Nonce[:], nonceAuthVote) && !bytes.Equal(header.Nonce[:], nonceDropVote) { 118 return errInvalidNonce 119 } 120 // Ensure that the mix digest is zero as we don't have fork protection currently 121 if header.MixDigest != types.BFTDigest { 122 return errInvalidMixDigest 123 } 124 // Ensure that the block doesn't contain any uncles which are meaningless in BFT 125 if header.UncleHash != nilUncleHash { 126 return errInvalidUncleHash 127 } 128 // Ensure that the block's difficulty is meaningful (may not be correct at this point) 129 if header.Difficulty == nil || header.Difficulty.Cmp(defaultDifficulty) != 0 { 130 return errInvalidDifficulty 131 } 132 133 return sb.verifyCascadingFields(chain, header, parents) 134 } 135 136 // verifyCascadingFields verifies all the header fields that are not standalone, 137 // rather depend on a batch of previous headers. The caller may optionally pass 138 // in a batch of parents (ascending order) to avoid looking those up from the 139 // database. This is useful for concurrently verifying a batch of new headers. 140 func (sb *backend) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 141 // The genesis block is the always valid dead-end 142 number := header.Number.Uint64() 143 if number == 0 { 144 return nil 145 } 146 // Ensure that the block's timestamp isn't too close to it's parent 147 var parent *types.Header 148 if len(parents) > 0 { 149 parent = parents[len(parents)-1] 150 } else { 151 parent = chain.GetHeader(header.ParentHash, number-1) 152 } 153 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 154 return consensus.ErrUnknownAncestor 155 } 156 if parent.Time.Uint64()+sb.config.BlockPeriod > header.Time.Uint64() { 157 return errInvalidTimestamp 158 } 159 // Verify validators in extraData. Validators in snapshot and extraData should be the same. 160 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents) 161 if err != nil { 162 return err 163 } 164 validators := make([]byte, len(snap.validators())*common.AddressLength) 165 for i, validator := range snap.validators() { 166 copy(validators[i*common.AddressLength:], validator[:]) 167 } 168 if err := sb.verifySigner(chain, header, parents); err != nil { 169 return err 170 } 171 172 return sb.verifyCommittedSeals(chain, header, parents) 173 } 174 175 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 176 // concurrently. The method returns a quit channel to abort the operations and 177 // a results channel to retrieve the async verifications (the order is that of 178 // the input slice). 179 func (sb *backend) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 180 abort := make(chan struct{}) 181 results := make(chan error, len(headers)) 182 go func() { 183 for i, header := range headers { 184 err := sb.verifyHeader(chain, header, headers[:i]) 185 186 select { 187 case <-abort: 188 return 189 case results <- err: 190 } 191 } 192 }() 193 return abort, results 194 } 195 196 // VerifyUncles verifies that the given block's uncles conform to the consensus 197 // rules of a given engine. 198 func (sb *backend) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 199 if len(block.Uncles()) > 0 { 200 return errInvalidUncleHash 201 } 202 return nil 203 } 204 205 // verifySigner checks whether the signer is in parent's validator set 206 func (sb *backend) verifySigner(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 207 // Verifying the genesis block is not supported 208 number := header.Number.Uint64() 209 if number == 0 { 210 return errUnknownBlock 211 } 212 213 // Retrieve the snapshot needed to verify this header and cache it 214 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents) 215 if err != nil { 216 return err 217 } 218 219 // resolve the authorization key and check against signers 220 signer, err := ecrecover(header) 221 if err != nil { 222 return err 223 } 224 225 // Signer should be in the validator set of previous block's extraData. 226 if _, v := snap.ValSet.GetByAddress(signer); v == nil { 227 return errUnauthorized 228 } 229 return nil 230 } 231 232 // verifyCommittedSeals checks whether every committed seal is signed by one of the parent's validators 233 func (sb *backend) verifyCommittedSeals(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 234 number := header.Number.Uint64() 235 // We don't need to verify committed seals in the genesis block 236 if number == 0 { 237 return nil 238 } 239 240 // Retrieve the snapshot needed to verify this header and cache it 241 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents) 242 if err != nil { 243 return err 244 } 245 246 extra, err := types.ExtractBFTExtra(header) 247 if err != nil { 248 return err 249 } 250 // The length of Committed seals should be larger than 0 251 if len(extra.CommittedSeal) == 0 { 252 return errEmptyCommittedSeals 253 } 254 255 validators := snap.ValSet.Copy() 256 // Check whether the committed seals are generated by parent's validators 257 validSeal := 0 258 proposalSeal := bftCore.PrepareCommittedSeal(header.Hash()) 259 // 1. Get committed seals from current header 260 for _, seal := range extra.CommittedSeal { 261 // 2. Get the original address by seal and parent block hash 262 addr, err := bft.GetSignatureAddress(proposalSeal, seal) 263 if err != nil { 264 sb.logger.Error("not a valid address", "err", err) 265 return errInvalidSignature 266 } 267 // Every validator can have only one seal. If more than one seals are signed by a 268 // validator, the validator cannot be found and errInvalidCommittedSeals is returned. 269 if validators.RemoveValidator(addr) { 270 validSeal += 1 271 } else { 272 return errInvalidCommittedSeals 273 } 274 } 275 276 // The length of validSeal should be larger than number of faulty node + 1 277 if validSeal <= 2*snap.ValSet.F() { 278 return errInvalidCommittedSeals 279 } 280 281 return nil 282 } 283 284 // VerifySeal checks whether the crypto seal on a header is valid according to 285 // the consensus rules of the given engine. 286 func (sb *backend) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 287 // get parent header and ensure the signer is in parent's validator set 288 number := header.Number.Uint64() 289 if number == 0 { 290 return errUnknownBlock 291 } 292 293 // ensure that the difficulty equals to defaultDifficulty 294 if header.Difficulty.Cmp(defaultDifficulty) != 0 { 295 return errInvalidDifficulty 296 } 297 return sb.verifySigner(chain, header, nil) 298 } 299 300 // Prepare initializes the consensus fields of a block header according to the 301 // rules of a particular engine. The changes are executed inline. 302 func (sb *backend) Prepare(chain consensus.ChainReader, header *types.Header) error { 303 // unused fields, force to set to empty 304 header.Coinbase = common.Address{} 305 header.Nonce = emptyNonce 306 header.MixDigest = types.BFTDigest 307 308 // copy the parent extra data as the header extra data 309 number := header.Number.Uint64() 310 parent := chain.GetHeader(header.ParentHash, number-1) 311 if parent == nil { 312 return consensus.ErrUnknownAncestor 313 } 314 // use the same difficulty for all blocks 315 header.Difficulty = defaultDifficulty 316 317 // Assemble the voting snapshot 318 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil) 319 if err != nil { 320 return err 321 } 322 323 // get valid candidate list 324 sb.candidatesLock.RLock() 325 var addresses []common.Address 326 var authorizes []bool 327 for address, authorize := range sb.candidates { 328 if snap.checkVote(address, authorize) { 329 addresses = append(addresses, address) 330 authorizes = append(authorizes, authorize) 331 } 332 } 333 sb.candidatesLock.RUnlock() 334 335 // pick one of the candidates randomly 336 if len(addresses) > 0 { 337 index := rand.Intn(len(addresses)) 338 // add validator voting in coinbase 339 header.Coinbase = addresses[index] 340 if authorizes[index] { 341 copy(header.Nonce[:], nonceAuthVote) 342 } else { 343 copy(header.Nonce[:], nonceDropVote) 344 } 345 } 346 347 // add validators in snapshot to extraData's validators section 348 extra, err := prepareExtra(header, snap.validators()) 349 if err != nil { 350 return err 351 } 352 header.Extra = extra 353 354 // set header's timestamp 355 header.Time = new(big.Int).Add(parent.Time, new(big.Int).SetUint64(sb.config.BlockPeriod)) 356 if header.Time.Int64() < time.Now().Unix() { 357 header.Time = big.NewInt(time.Now().Unix()) 358 } 359 return nil 360 } 361 362 // Judge the create contract Transaction from a no authorized account for clique engine. 363 func (sb *backend) JudgeTx(chain consensus.ChainReader, header *types.Header, tx *types.Transaction, from common.Address) error { 364 /* 365 // get the number of the new block 366 number := header.Number.Uint64() 367 //log.Info("PrepareTx number ","number", number) 368 // get current block sanpshot 369 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil) 370 if err != nil { 371 return err 372 } 373 //log.Info("PrepareTx get snapshot ") 374 if tx.To() == nil { 375 //log.Info("PrepareTx tx.To() == nil") 376 //judge a account is not a authorizer 377 if _, authorized := snap.Signers[from]; !authorized { 378 log.Info("PrepareTx create contract no authorized", "from", from) 379 return errUnauthorized 380 } else { 381 log.Info("PrepareTx create contract authorized", "from", from) 382 } 383 } else { 384 //log.Info("PrepareTx tx.To() != nil", "from", from) 385 }*/ 386 return nil 387 } 388 389 // Finalize runs any post-transaction state modifications (e.g. block rewards) 390 // and assembles the final block. 391 // 392 // Note, the block header and state database might be updated to reflect any 393 // consensus rules that happen at finalization (e.g. block rewards). 394 func (sb *backend) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 395 uncles []*types.Header, receipts []*types.Receipt, dposContext *types.DposContext) (*types.Block, error) { 396 // No block rewards in BFT, so the state remains as is and uncles are dropped 397 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 398 header.UncleHash = nilUncleHash 399 header.DposContext = dposContext.ToProto() 400 401 // Assemble and return the final block for sealing 402 block := types.NewBlock(header, txs, nil, receipts) 403 block.DposContext = dposContext 404 return block, nil 405 } 406 407 // Seal generates a new block for the given input block with the local miner's 408 // seal place on top. 409 func (sb *backend) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { 410 // update the block header timestamp and signature and propose the block to core engine 411 header := block.Header() 412 number := header.Number.Uint64() 413 414 // Bail out if we're unauthorized to sign a block 415 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil) 416 if err != nil { 417 return nil, err 418 } 419 if _, v := snap.ValSet.GetByAddress(sb.address); v == nil { 420 return nil, errUnauthorized 421 } 422 423 parent := chain.GetHeader(header.ParentHash, number-1) 424 if parent == nil { 425 return nil, consensus.ErrUnknownAncestor 426 } 427 block, err = sb.updateBlock(parent, block) 428 if err != nil { 429 return nil, err 430 } 431 432 // wait for the timestamp of header, use this to adjust the block period 433 delay := time.Unix(block.Header().Time.Int64(), 0).Sub(now()) 434 select { 435 case <-time.After(delay): 436 case <-stop: 437 return nil, nil 438 } 439 440 // get the proposed block hash and clear it if the seal() is completed. 441 sb.sealMu.Lock() 442 sb.proposedBlockHash = block.Hash() 443 clear := func() { 444 sb.proposedBlockHash = common.Hash{} 445 sb.sealMu.Unlock() 446 } 447 defer clear() 448 449 // post block into BFT engine 450 go sb.EventMux().Post(bft.RequestEvent{ 451 Proposal: block, 452 }) 453 454 for { 455 select { 456 case result := <-sb.commitCh: 457 // if the block hash and the hash from channel are the same, 458 // return the result. Otherwise, keep waiting the next hash. 459 if block.Hash() == result.Hash() { 460 return result, nil 461 } 462 case <-stop: 463 return nil, nil 464 } 465 } 466 } 467 468 // update timestamp and signature of the block based on its number of transactions 469 func (sb *backend) updateBlock(parent *types.Header, block *types.Block) (*types.Block, error) { 470 header := block.Header() 471 // sign the hash 472 seal, err := sb.Sign(sigHash(header).Bytes()) 473 if err != nil { 474 return nil, err 475 } 476 477 err = writeSeal(header, seal) 478 if err != nil { 479 return nil, err 480 } 481 482 return block.WithSeal(header), nil 483 } 484 485 // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty 486 // that a new block should have based on the previous blocks in the chain and the 487 // current signer. 488 func (sb *backend) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 489 490 return defaultDifficulty 491 } 492 493 // APIs returns the RPC APIs this consensus engine provides. 494 func (sb *backend) APIs(chain consensus.ChainReader) []rpc.API { 495 return []rpc.API{{ 496 Namespace: "bft", 497 Version: "1.0", 498 Service: &API{chain: chain, bft: sb}, 499 Public: true, 500 }} 501 } 502 503 // Start implements consensus.BFT.Start 504 func (sb *backend) Start(chain consensus.ChainReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error { 505 sb.coreMu.Lock() 506 defer sb.coreMu.Unlock() 507 if sb.coreStarted { 508 return bft.ErrStartedEngine 509 } 510 511 // clear previous data 512 sb.proposedBlockHash = common.Hash{} 513 if sb.commitCh != nil { 514 close(sb.commitCh) 515 } 516 sb.commitCh = make(chan *types.Block, 1) 517 518 sb.chain = chain 519 sb.currentBlock = currentBlock 520 sb.hasBadBlock = hasBadBlock 521 522 if err := sb.core.Start(); err != nil { 523 return err 524 } 525 526 sb.coreStarted = true 527 return nil 528 } 529 530 // Stop implements consensus.BFT.Stop 531 func (sb *backend) Stop() error { 532 sb.coreMu.Lock() 533 defer sb.coreMu.Unlock() 534 if !sb.coreStarted { 535 return bft.ErrStoppedEngine 536 } 537 if err := sb.core.Stop(); err != nil { 538 return err 539 } 540 sb.coreStarted = false 541 return nil 542 } 543 544 // snapshot retrieves the authorization snapshot at a given point in time. 545 func (sb *backend) snapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) { 546 // Search for a snapshot in memory or on disk for checkpoints 547 var ( 548 headers []*types.Header 549 snap *Snapshot 550 ) 551 for snap == nil { 552 // If an in-memory snapshot was found, use that 553 if s, ok := sb.recents.Get(hash); ok { 554 snap = s.(*Snapshot) 555 break 556 } 557 // If an on-disk checkpoint snapshot can be found, use that 558 if number%checkpointInterval == 0 { 559 if s, err := loadSnapshot(sb.config.Epoch, sb.db, hash); err == nil { 560 log.Trace("Loaded voting snapshot form disk", "number", number, "hash", hash) 561 snap = s 562 break 563 } 564 } 565 // If we're at block zero, make a snapshot 566 if number == 0 { 567 genesis := chain.GetHeaderByNumber(0) 568 if err := sb.VerifyHeader(chain, genesis, false); err != nil { 569 return nil, err 570 } 571 bftExtra, err := types.ExtractBFTExtra(genesis) 572 if err != nil { 573 return nil, err 574 } 575 snap = newSnapshot(sb.config.Epoch, 0, genesis.Hash(), validator.NewSet(bftExtra.Validators, sb.config.ProposerPolicy)) 576 if err := snap.store(sb.db); err != nil { 577 return nil, err 578 } 579 log.Trace("Stored genesis voting snapshot to disk") 580 break 581 } 582 // No snapshot for this header, gather the header and move backward 583 var header *types.Header 584 if len(parents) > 0 { 585 // If we have explicit parents, pick from there (enforced) 586 header = parents[len(parents)-1] 587 if header.Hash() != hash || header.Number.Uint64() != number { 588 return nil, consensus.ErrUnknownAncestor 589 } 590 parents = parents[:len(parents)-1] 591 } else { 592 // No explicit parents (or no more left), reach out to the database 593 header = chain.GetHeader(hash, number) 594 if header == nil { 595 return nil, consensus.ErrUnknownAncestor 596 } 597 } 598 headers = append(headers, header) 599 number, hash = number-1, header.ParentHash 600 } 601 // Previous snapshot found, apply any pending headers on top of it 602 for i := 0; i < len(headers)/2; i++ { 603 headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i] 604 } 605 snap, err := snap.apply(headers) 606 if err != nil { 607 return nil, err 608 } 609 sb.recents.Add(snap.Hash, snap) 610 611 // If we've generated a new checkpoint snapshot, save to disk 612 if snap.Number%checkpointInterval == 0 && len(headers) > 0 { 613 if err = snap.store(sb.db); err != nil { 614 return nil, err 615 } 616 log.Trace("Stored voting snapshot to disk", "number", snap.Number, "hash", snap.Hash) 617 } 618 return snap, err 619 } 620 621 // FIXME: Need to update this for BFT 622 // sigHash returns the hash which is used as input for the BFT 623 // signing. It is the hash of the entire header apart from the 65 byte signature 624 // contained at the end of the extra data. 625 // 626 // Note, the method requires the extra data to be at least 65 bytes, otherwise it 627 // panics. This is done to avoid accidentally using both forms (signature present 628 // or not), which could be abused to produce different hashes for the same header. 629 func sigHash(header *types.Header) (hash common.Hash) { 630 hasher := sha3.NewKeccak256() 631 632 // Clean seal is required for calculating proposer seal. 633 rlp.Encode(hasher, types.BFTFilteredHeader(header, false)) 634 hasher.Sum(hash[:0]) 635 return hash 636 } 637 638 // ecrecover extracts the Ethereum account address from a signed header. 639 func ecrecover(header *types.Header) (common.Address, error) { 640 hash := header.Hash() 641 if addr, ok := recentAddresses.Get(hash); ok { 642 return addr.(common.Address), nil 643 } 644 645 // Retrieve the signature from the header extra-data 646 bftExtra, err := types.ExtractBFTExtra(header) 647 if err != nil { 648 return common.Address{}, err 649 } 650 651 addr, err := bft.GetSignatureAddress(sigHash(header).Bytes(), bftExtra.Seal) 652 if err != nil { 653 return addr, err 654 } 655 recentAddresses.Add(hash, addr) 656 return addr, nil 657 } 658 659 // prepareExtra returns a extra-data of the given header and validators 660 func prepareExtra(header *types.Header, vals []common.Address) ([]byte, error) { 661 var buf bytes.Buffer 662 663 // compensate the lack bytes if header.Extra is not enough BFTExtraVanity bytes. 664 if len(header.Extra) < types.BFTExtraVanity { 665 header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, types.BFTExtraVanity-len(header.Extra))...) 666 } 667 buf.Write(header.Extra[:types.BFTExtraVanity]) 668 669 ist := &types.BFTExtra{ 670 Validators: vals, 671 Seal: []byte{}, 672 CommittedSeal: [][]byte{}, 673 } 674 675 payload, err := rlp.EncodeToBytes(&ist) 676 if err != nil { 677 return nil, err 678 } 679 680 return append(buf.Bytes(), payload...), nil 681 } 682 683 // writeSeal writes the extra-data field of the given header with the given seals. 684 // suggest to rename to writeSeal. 685 func writeSeal(h *types.Header, seal []byte) error { 686 if len(seal)%types.BFTExtraSeal != 0 { 687 return errInvalidSignature 688 } 689 690 bftExtra, err := types.ExtractBFTExtra(h) 691 if err != nil { 692 return err 693 } 694 695 bftExtra.Seal = seal 696 payload, err := rlp.EncodeToBytes(&bftExtra) 697 if err != nil { 698 return err 699 } 700 701 h.Extra = append(h.Extra[:types.BFTExtraVanity], payload...) 702 return nil 703 } 704 705 // writeCommittedSeals writes the extra-data field of a block header with given committed seals. 706 func writeCommittedSeals(h *types.Header, committedSeals [][]byte) error { 707 if len(committedSeals) == 0 { 708 return errInvalidCommittedSeals 709 } 710 711 for _, seal := range committedSeals { 712 if len(seal) != types.BFTExtraSeal { 713 return errInvalidCommittedSeals 714 } 715 } 716 717 bftExtra, err := types.ExtractBFTExtra(h) 718 if err != nil { 719 return err 720 } 721 722 bftExtra.CommittedSeal = make([][]byte, len(committedSeals)) 723 copy(bftExtra.CommittedSeal, committedSeals) 724 725 payload, err := rlp.EncodeToBytes(&bftExtra) 726 if err != nil { 727 return err 728 } 729 730 h.Extra = append(h.Extra[:types.BFTExtraVanity], payload...) 731 return nil 732 }