github.com/ConsenSys/Quorum@v20.10.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 istanbulCore "github.com/ethereum/go-ethereum/consensus/istanbul/core" 31 "github.com/ethereum/go-ethereum/consensus/istanbul/validator" 32 "github.com/ethereum/go-ethereum/core/state" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/log" 35 "github.com/ethereum/go-ethereum/rlp" 36 "github.com/ethereum/go-ethereum/rpc" 37 lru "github.com/hashicorp/golang-lru" 38 "golang.org/x/crypto/sha3" 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 transactions 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 (adjusting for allowed threshold) 148 adjustedTimeNow := now().Add(time.Duration(sb.config.AllowedFutureBlockTime) * time.Second).Unix() 149 if header.Time > uint64(adjustedTimeNow) { 150 return consensus.ErrFutureBlock 151 } 152 153 // Ensure that the extra data format is satisfied 154 if _, err := types.ExtractIstanbulExtra(header); err != nil { 155 return errInvalidExtraDataFormat 156 } 157 158 // Ensure that the coinbase is valid 159 if header.Nonce != (emptyNonce) && !bytes.Equal(header.Nonce[:], nonceAuthVote) && !bytes.Equal(header.Nonce[:], nonceDropVote) { 160 return errInvalidNonce 161 } 162 // Ensure that the mix digest is zero as we don't have fork protection currently 163 if header.MixDigest != types.IstanbulDigest { 164 return errInvalidMixDigest 165 } 166 // Ensure that the block doesn't contain any uncles which are meaningless in Istanbul 167 if header.UncleHash != nilUncleHash { 168 return errInvalidUncleHash 169 } 170 // Ensure that the block's difficulty is meaningful (may not be correct at this point) 171 if header.Difficulty == nil || header.Difficulty.Cmp(defaultDifficulty) != 0 { 172 return errInvalidDifficulty 173 } 174 175 return sb.verifyCascadingFields(chain, header, parents) 176 } 177 178 // verifyCascadingFields verifies all the header fields that are not standalone, 179 // rather depend on a batch of previous headers. The caller may optionally pass 180 // in a batch of parents (ascending order) to avoid looking those up from the 181 // database. This is useful for concurrently verifying a batch of new headers. 182 func (sb *backend) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 183 // The genesis block is the always valid dead-end 184 number := header.Number.Uint64() 185 if number == 0 { 186 return nil 187 } 188 // Ensure that the block's timestamp isn't too close to it's parent 189 var parent *types.Header 190 if len(parents) > 0 { 191 parent = parents[len(parents)-1] 192 } else { 193 parent = chain.GetHeader(header.ParentHash, number-1) 194 } 195 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 196 return consensus.ErrUnknownAncestor 197 } 198 if parent.Time+sb.config.BlockPeriod > header.Time { 199 return errInvalidTimestamp 200 } 201 // Verify validators in extraData. Validators in snapshot and extraData should be the same. 202 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents) 203 if err != nil { 204 return err 205 } 206 validators := make([]byte, len(snap.validators())*common.AddressLength) 207 for i, validator := range snap.validators() { 208 copy(validators[i*common.AddressLength:], validator[:]) 209 } 210 if err := sb.verifySigner(chain, header, parents); err != nil { 211 return err 212 } 213 214 return sb.verifyCommittedSeals(chain, header, parents) 215 } 216 217 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 218 // concurrently. The method returns a quit channel to abort the operations and 219 // a results channel to retrieve the async verifications (the order is that of 220 // the input slice). 221 func (sb *backend) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 222 abort := make(chan struct{}) 223 results := make(chan error, len(headers)) 224 go func() { 225 errored := false 226 for i, header := range headers { 227 var err error 228 if errored { 229 err = consensus.ErrUnknownAncestor 230 } else { 231 err = sb.verifyHeader(chain, header, headers[:i]) 232 } 233 234 if err != nil { 235 errored = true 236 } 237 238 select { 239 case <-abort: 240 return 241 case results <- err: 242 } 243 } 244 }() 245 return abort, results 246 } 247 248 // VerifyUncles verifies that the given block's uncles conform to the consensus 249 // rules of a given engine. 250 func (sb *backend) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 251 if len(block.Uncles()) > 0 { 252 return errInvalidUncleHash 253 } 254 return nil 255 } 256 257 // verifySigner checks whether the signer is in parent's validator set 258 func (sb *backend) verifySigner(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 259 // Verifying the genesis block is not supported 260 number := header.Number.Uint64() 261 if number == 0 { 262 return errUnknownBlock 263 } 264 265 // Retrieve the snapshot needed to verify this header and cache it 266 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents) 267 if err != nil { 268 return err 269 } 270 271 // resolve the authorization key and check against signers 272 signer, err := ecrecover(header) 273 if err != nil { 274 return err 275 } 276 277 // Signer should be in the validator set of previous block's extraData. 278 if _, v := snap.ValSet.GetByAddress(signer); v == nil { 279 return errUnauthorized 280 } 281 return nil 282 } 283 284 // verifyCommittedSeals checks whether every committed seal is signed by one of the parent's validators 285 func (sb *backend) verifyCommittedSeals(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 286 number := header.Number.Uint64() 287 // We don't need to verify committed seals in the genesis block 288 if number == 0 { 289 return nil 290 } 291 292 // Retrieve the snapshot needed to verify this header and cache it 293 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents) 294 if err != nil { 295 return err 296 } 297 298 extra, err := types.ExtractIstanbulExtra(header) 299 if err != nil { 300 return err 301 } 302 // The length of Committed seals should be larger than 0 303 if len(extra.CommittedSeal) == 0 { 304 return errEmptyCommittedSeals 305 } 306 307 validators := snap.ValSet.Copy() 308 // Check whether the committed seals are generated by parent's validators 309 validSeal := 0 310 committers, err := sb.Signers(header) 311 if err != nil { 312 return err 313 } 314 for _, addr := range committers { 315 if validators.RemoveValidator(addr) { 316 validSeal++ 317 continue 318 } 319 return errInvalidCommittedSeals 320 } 321 322 // The length of validSeal should be larger than number of faulty node + 1 323 if validSeal <= snap.ValSet.F() { 324 return errInvalidCommittedSeals 325 } 326 327 return nil 328 } 329 330 // VerifySeal checks whether the crypto seal on a header is valid according to 331 // the consensus rules of the given engine. 332 func (sb *backend) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 333 // get parent header and ensure the signer is in parent's validator set 334 number := header.Number.Uint64() 335 if number == 0 { 336 return errUnknownBlock 337 } 338 339 // ensure that the difficulty equals to defaultDifficulty 340 if header.Difficulty.Cmp(defaultDifficulty) != 0 { 341 return errInvalidDifficulty 342 } 343 return sb.verifySigner(chain, header, nil) 344 } 345 346 // Prepare initializes the consensus fields of a block header according to the 347 // rules of a particular engine. The changes are executed inline. 348 func (sb *backend) Prepare(chain consensus.ChainReader, header *types.Header) error { 349 // unused fields, force to set to empty 350 header.Coinbase = common.Address{} 351 header.Nonce = emptyNonce 352 header.MixDigest = types.IstanbulDigest 353 354 // copy the parent extra data as the header extra data 355 number := header.Number.Uint64() 356 parent := chain.GetHeader(header.ParentHash, number-1) 357 if parent == nil { 358 return consensus.ErrUnknownAncestor 359 } 360 // use the same difficulty for all blocks 361 header.Difficulty = defaultDifficulty 362 363 // Assemble the voting snapshot 364 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil) 365 if err != nil { 366 return err 367 } 368 369 // get valid candidate list 370 sb.candidatesLock.RLock() 371 var addresses []common.Address 372 var authorizes []bool 373 for address, authorize := range sb.candidates { 374 if snap.checkVote(address, authorize) { 375 addresses = append(addresses, address) 376 authorizes = append(authorizes, authorize) 377 } 378 } 379 sb.candidatesLock.RUnlock() 380 381 // pick one of the candidates randomly 382 if len(addresses) > 0 { 383 index := rand.Intn(len(addresses)) 384 // add validator voting in coinbase 385 header.Coinbase = addresses[index] 386 if authorizes[index] { 387 copy(header.Nonce[:], nonceAuthVote) 388 } else { 389 copy(header.Nonce[:], nonceDropVote) 390 } 391 } 392 393 // add validators in snapshot to extraData's validators section 394 extra, err := prepareExtra(header, snap.validators()) 395 if err != nil { 396 return err 397 } 398 header.Extra = extra 399 400 // set header's timestamp 401 header.Time = parent.Time + sb.config.BlockPeriod 402 if header.Time < uint64(time.Now().Unix()) { 403 header.Time = uint64(time.Now().Unix()) 404 } 405 return nil 406 } 407 408 // Finalize runs any post-transaction state modifications (e.g. block rewards) 409 // and assembles the final block. 410 // 411 // Note, the block header and state database might be updated to reflect any 412 // consensus rules that happen at finalization (e.g. block rewards). 413 func (sb *backend) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 414 uncles []*types.Header) { 415 // No block rewards in Istanbul, so the state remains as is and uncles are dropped 416 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 417 header.UncleHash = nilUncleHash 418 } 419 420 // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, 421 // nor block rewards given, and returns the final block. 422 func (sb *backend) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { 423 /// No block rewards in Istanbul, so the state remains as is and uncles are dropped 424 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 425 header.UncleHash = nilUncleHash 426 427 // Assemble and return the final block for sealing 428 return types.NewBlock(header, txs, nil, receipts), nil 429 } 430 431 // Seal generates a new block for the given input block with the local miner's 432 // seal place on top. 433 func (sb *backend) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { 434 435 // update the block header timestamp and signature and propose the block to core engine 436 header := block.Header() 437 number := header.Number.Uint64() 438 // Bail out if we're unauthorized to sign a block 439 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil) 440 if err != nil { 441 return err 442 } 443 if _, v := snap.ValSet.GetByAddress(sb.address); v == nil { 444 return errUnauthorized 445 } 446 447 parent := chain.GetHeader(header.ParentHash, number-1) 448 if parent == nil { 449 return consensus.ErrUnknownAncestor 450 } 451 block, err = sb.updateBlock(parent, block) 452 if err != nil { 453 return err 454 } 455 456 delay := time.Unix(int64(block.Header().Time), 0).Sub(now()) 457 458 go func() { 459 // wait for the timestamp of header, use this to adjust the block period 460 select { 461 case <-time.After(delay): 462 case <-stop: 463 results <- nil 464 return 465 } 466 467 // get the proposed block hash and clear it if the seal() is completed. 468 sb.sealMu.Lock() 469 sb.proposedBlockHash = block.Hash() 470 471 defer func() { 472 sb.proposedBlockHash = common.Hash{} 473 sb.sealMu.Unlock() 474 }() 475 // post block into Istanbul engine 476 go sb.EventMux().Post(istanbul.RequestEvent{ 477 Proposal: block, 478 }) 479 for { 480 select { 481 case result := <-sb.commitCh: 482 // if the block hash and the hash from channel are the same, 483 // return the result. Otherwise, keep waiting the next hash. 484 if result != nil && block.Hash() == result.Hash() { 485 results <- result 486 return 487 } 488 case <-stop: 489 results <- nil 490 return 491 } 492 } 493 }() 494 return nil 495 } 496 497 // update timestamp and signature of the block based on its number of transactions 498 func (sb *backend) updateBlock(parent *types.Header, block *types.Block) (*types.Block, error) { 499 header := block.Header() 500 // sign the hash 501 seal, err := sb.Sign(sigHash(header).Bytes()) 502 if err != nil { 503 return nil, err 504 } 505 506 err = writeSeal(header, seal) 507 if err != nil { 508 return nil, err 509 } 510 511 return block.WithSeal(header), nil 512 } 513 514 // APIs returns the RPC APIs this consensus engine provides. 515 func (sb *backend) APIs(chain consensus.ChainReader) []rpc.API { 516 return []rpc.API{{ 517 Namespace: "istanbul", 518 Version: "1.0", 519 Service: &API{chain: chain, istanbul: sb}, 520 Public: true, 521 }} 522 } 523 524 // Start implements consensus.Istanbul.Start 525 func (sb *backend) Start(chain consensus.ChainReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error { 526 sb.coreMu.Lock() 527 defer sb.coreMu.Unlock() 528 if sb.coreStarted { 529 return istanbul.ErrStartedEngine 530 } 531 532 // clear previous data 533 sb.proposedBlockHash = common.Hash{} 534 if sb.commitCh != nil { 535 close(sb.commitCh) 536 } 537 sb.commitCh = make(chan *types.Block, 1) 538 539 sb.chain = chain 540 sb.currentBlock = currentBlock 541 sb.hasBadBlock = hasBadBlock 542 543 if err := sb.core.Start(); err != nil { 544 return err 545 } 546 547 sb.coreStarted = true 548 return nil 549 } 550 551 // Stop implements consensus.Istanbul.Stop 552 func (sb *backend) Stop() error { 553 sb.coreMu.Lock() 554 defer sb.coreMu.Unlock() 555 if !sb.coreStarted { 556 return istanbul.ErrStoppedEngine 557 } 558 if err := sb.core.Stop(); err != nil { 559 return err 560 } 561 sb.coreStarted = false 562 return nil 563 } 564 565 // snapshot retrieves the authorization snapshot at a given point in time. 566 func (sb *backend) snapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) { 567 // Search for a snapshot in memory or on disk for checkpoints 568 var ( 569 headers []*types.Header 570 snap *Snapshot 571 ) 572 for snap == nil { 573 // If an in-memory snapshot was found, use that 574 if s, ok := sb.recents.Get(hash); ok { 575 snap = s.(*Snapshot) 576 break 577 } 578 // If an on-disk checkpoint snapshot can be found, use that 579 if number%checkpointInterval == 0 { 580 if s, err := loadSnapshot(sb.config.Epoch, sb.db, hash); err == nil { 581 log.Trace("Loaded voting snapshot form disk", "number", number, "hash", hash) 582 snap = s 583 break 584 } 585 } 586 // If we're at block zero, make a snapshot 587 if number == 0 { 588 genesis := chain.GetHeaderByNumber(0) 589 if err := sb.VerifyHeader(chain, genesis, false); err != nil { 590 return nil, err 591 } 592 istanbulExtra, err := types.ExtractIstanbulExtra(genesis) 593 if err != nil { 594 return nil, err 595 } 596 snap = newSnapshot(sb.config.Epoch, 0, genesis.Hash(), validator.NewSet(istanbulExtra.Validators, sb.config.ProposerPolicy)) 597 if err := snap.store(sb.db); err != nil { 598 return nil, err 599 } 600 log.Trace("Stored genesis voting snapshot to disk") 601 break 602 } 603 // No snapshot for this header, gather the header and move backward 604 var header *types.Header 605 if len(parents) > 0 { 606 // If we have explicit parents, pick from there (enforced) 607 header = parents[len(parents)-1] 608 if header.Hash() != hash || header.Number.Uint64() != number { 609 return nil, consensus.ErrUnknownAncestor 610 } 611 parents = parents[:len(parents)-1] 612 } else { 613 // No explicit parents (or no more left), reach out to the database 614 header = chain.GetHeader(hash, number) 615 if header == nil { 616 return nil, consensus.ErrUnknownAncestor 617 } 618 } 619 headers = append(headers, header) 620 number, hash = number-1, header.ParentHash 621 } 622 // Previous snapshot found, apply any pending headers on top of it 623 for i := 0; i < len(headers)/2; i++ { 624 headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i] 625 } 626 snap, err := snap.apply(headers) 627 if err != nil { 628 return nil, err 629 } 630 sb.recents.Add(snap.Hash, snap) 631 632 // If we've generated a new checkpoint snapshot, save to disk 633 if snap.Number%checkpointInterval == 0 && len(headers) > 0 { 634 if err = snap.store(sb.db); err != nil { 635 return nil, err 636 } 637 log.Trace("Stored voting snapshot to disk", "number", snap.Number, "hash", snap.Hash) 638 } 639 return snap, err 640 } 641 642 // FIXME: Need to update this for Istanbul 643 // sigHash returns the hash which is used as input for the Istanbul 644 // signing. It is the hash of the entire header apart from the 65 byte signature 645 // contained at the end of the extra data. 646 // 647 // Note, the method requires the extra data to be at least 65 bytes, otherwise it 648 // panics. This is done to avoid accidentally using both forms (signature present 649 // or not), which could be abused to produce different hashes for the same header. 650 func sigHash(header *types.Header) (hash common.Hash) { 651 hasher := sha3.NewLegacyKeccak256() 652 653 // Clean seal is required for calculating proposer seal. 654 rlp.Encode(hasher, types.IstanbulFilteredHeader(header, false)) 655 hasher.Sum(hash[:0]) 656 return hash 657 } 658 659 // SealHash returns the hash of a block prior to it being sealed. 660 func (sb *backend) SealHash(header *types.Header) common.Hash { 661 return sigHash(header) 662 } 663 664 // ecrecover extracts the Ethereum account address from a signed header. 665 func ecrecover(header *types.Header) (common.Address, error) { 666 hash := header.Hash() 667 if addr, ok := recentAddresses.Get(hash); ok { 668 return addr.(common.Address), nil 669 } 670 671 // Retrieve the signature from the header extra-data 672 istanbulExtra, err := types.ExtractIstanbulExtra(header) 673 if err != nil { 674 return common.Address{}, err 675 } 676 677 addr, err := istanbul.GetSignatureAddress(sigHash(header).Bytes(), istanbulExtra.Seal) 678 if err != nil { 679 return addr, err 680 } 681 recentAddresses.Add(hash, addr) 682 return addr, nil 683 } 684 685 // prepareExtra returns a extra-data of the given header and validators 686 func prepareExtra(header *types.Header, vals []common.Address) ([]byte, error) { 687 var buf bytes.Buffer 688 689 // compensate the lack bytes if header.Extra is not enough IstanbulExtraVanity bytes. 690 if len(header.Extra) < types.IstanbulExtraVanity { 691 header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity-len(header.Extra))...) 692 } 693 buf.Write(header.Extra[:types.IstanbulExtraVanity]) 694 695 ist := &types.IstanbulExtra{ 696 Validators: vals, 697 Seal: []byte{}, 698 CommittedSeal: [][]byte{}, 699 } 700 701 payload, err := rlp.EncodeToBytes(&ist) 702 if err != nil { 703 return nil, err 704 } 705 706 return append(buf.Bytes(), payload...), nil 707 } 708 709 // writeSeal writes the extra-data field of the given header with the given seals. 710 // suggest to rename to writeSeal. 711 func writeSeal(h *types.Header, seal []byte) error { 712 if len(seal)%types.IstanbulExtraSeal != 0 { 713 return errInvalidSignature 714 } 715 716 istanbulExtra, err := types.ExtractIstanbulExtra(h) 717 if err != nil { 718 return err 719 } 720 721 istanbulExtra.Seal = seal 722 payload, err := rlp.EncodeToBytes(&istanbulExtra) 723 if err != nil { 724 return err 725 } 726 727 h.Extra = append(h.Extra[:types.IstanbulExtraVanity], payload...) 728 return nil 729 } 730 731 // writeCommittedSeals writes the extra-data field of a block header with given committed seals. 732 func writeCommittedSeals(h *types.Header, committedSeals [][]byte) error { 733 if len(committedSeals) == 0 { 734 return errInvalidCommittedSeals 735 } 736 737 for _, seal := range committedSeals { 738 if len(seal) != types.IstanbulExtraSeal { 739 return errInvalidCommittedSeals 740 } 741 } 742 743 istanbulExtra, err := types.ExtractIstanbulExtra(h) 744 if err != nil { 745 return err 746 } 747 748 istanbulExtra.CommittedSeal = make([][]byte, len(committedSeals)) 749 copy(istanbulExtra.CommittedSeal, committedSeals) 750 751 payload, err := rlp.EncodeToBytes(&istanbulExtra) 752 if err != nil { 753 return err 754 } 755 756 h.Extra = append(h.Extra[:types.IstanbulExtraVanity], payload...) 757 return nil 758 }