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