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