github.com/klaytn/klaytn@v1.10.2/consensus/istanbul/backend/engine.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from quorum/consensus/istanbul/backend/engine.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package backend 22 23 import ( 24 "bytes" 25 "encoding/hex" 26 "encoding/json" 27 "errors" 28 "math/big" 29 "time" 30 31 lru "github.com/hashicorp/golang-lru" 32 "github.com/klaytn/klaytn/blockchain/state" 33 "github.com/klaytn/klaytn/blockchain/types" 34 "github.com/klaytn/klaytn/common" 35 "github.com/klaytn/klaytn/common/hexutil" 36 "github.com/klaytn/klaytn/consensus" 37 "github.com/klaytn/klaytn/consensus/istanbul" 38 istanbulCore "github.com/klaytn/klaytn/consensus/istanbul/core" 39 "github.com/klaytn/klaytn/consensus/istanbul/validator" 40 "github.com/klaytn/klaytn/consensus/misc" 41 "github.com/klaytn/klaytn/crypto/sha3" 42 "github.com/klaytn/klaytn/networks/rpc" 43 "github.com/klaytn/klaytn/reward" 44 "github.com/klaytn/klaytn/rlp" 45 ) 46 47 const ( 48 // checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database 49 // inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory 50 // inmemoryPeers = 40 51 // inmemoryMessages = 1024 52 53 checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database 54 inmemorySnapshots = 496 // Number of recent vote snapshots to keep in memory 55 inmemoryPeers = 200 56 inmemoryMessages = 4096 57 58 allowedFutureBlockTime = 1 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks 59 ) 60 61 var ( 62 // errInvalidProposal is returned when a prposal is malformed. 63 errInvalidProposal = errors.New("invalid proposal") 64 // errInvalidSignature is returned when given signature is not signed by given 65 // address. 66 errInvalidSignature = errors.New("invalid signature") 67 // errUnknownBlock is returned when the list of validators is requested for a block 68 // that is not part of the local blockchain. 69 errUnknownBlock = errors.New("unknown block") 70 // errUnauthorized is returned if a header is signed by a non authorized entity. 71 errUnauthorized = errors.New("unauthorized") 72 // errInvalidBlockScore is returned if the BlockScore of a block is not 1 73 errInvalidBlockScore = errors.New("invalid blockscore") 74 // errInvalidExtraDataFormat is returned when the extra data format is incorrect 75 errInvalidExtraDataFormat = errors.New("invalid extra data format") 76 // errInvalidTimestamp is returned if the timestamp of a block is lower than the previous block's timestamp + the minimum block period. 77 errInvalidTimestamp = errors.New("invalid timestamp") 78 // errInvalidVotingChain is returned if an authorization list is attempted to 79 // be modified via out-of-range or non-contiguous headers. 80 errInvalidVotingChain = errors.New("invalid voting chain") 81 // errInvalidVote is returned if a nonce value is something else that the two 82 // allowed constants of 0x00..0 or 0xff..f. 83 errInvalidVote = errors.New("vote nonce not 0x00..0 or 0xff..f") 84 // errInvalidCommittedSeals is returned if the committed seal is not signed by any of parent validators. 85 errInvalidCommittedSeals = errors.New("invalid committed seals") 86 // errEmptyCommittedSeals is returned if the field of committed seals is zero. 87 errEmptyCommittedSeals = errors.New("zero committed seals") 88 // errMismatchTxhashes is returned if the TxHash in header is mismatch. 89 errMismatchTxhashes = errors.New("mismatch transactions hashes") 90 ) 91 92 var ( 93 defaultBlockScore = big.NewInt(1) 94 now = time.Now 95 96 nonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new validator 97 nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a validator. 98 99 inmemoryBlocks = 2048 // Number of blocks to precompute validators' addresses 100 inmemoryValidatorsPerBlock = 30 // Approximate number of validators' addresses from ecrecover 101 signatureAddresses, _ = lru.NewARC(inmemoryBlocks * inmemoryValidatorsPerBlock) 102 ) 103 104 // cacheSignatureAddresses extracts the address from the given data and signature and cache them for later usage. 105 func cacheSignatureAddresses(data []byte, sig []byte) (common.Address, error) { 106 sigStr := hex.EncodeToString(sig) 107 if addr, ok := signatureAddresses.Get(sigStr); ok { 108 return addr.(common.Address), nil 109 } 110 addr, err := istanbul.GetSignatureAddress(data, sig) 111 if err != nil { 112 return common.Address{}, err 113 } 114 signatureAddresses.Add(sigStr, addr) 115 return addr, err 116 } 117 118 // Author retrieves the Klaytn address of the account that minted the given block. 119 func (sb *backend) Author(header *types.Header) (common.Address, error) { 120 return ecrecover(header) 121 } 122 123 // CanVerifyHeadersConcurrently returns true if concurrent header verification possible, otherwise returns false. 124 func (sb *backend) CanVerifyHeadersConcurrently() bool { 125 return false 126 } 127 128 // PreprocessHeaderVerification prepares header verification for heavy computation before synchronous header verification such as ecrecover. 129 func (sb *backend) PreprocessHeaderVerification(headers []*types.Header) (chan<- struct{}, <-chan error) { 130 abort := make(chan struct{}) 131 results := make(chan error, inmemoryBlocks) 132 go func() { 133 for _, header := range headers { 134 err := sb.computeSignatureAddrs(header) 135 136 select { 137 case <-abort: 138 return 139 case results <- err: 140 } 141 } 142 }() 143 return abort, results 144 } 145 146 // computeSignatureAddrs computes the addresses of signer and validators and caches them. 147 func (sb *backend) computeSignatureAddrs(header *types.Header) error { 148 _, err := ecrecover(header) 149 if err != nil { 150 return err 151 } 152 153 // Retrieve the signature from the header extra-data 154 istanbulExtra, err := types.ExtractIstanbulExtra(header) 155 if err != nil { 156 return err 157 } 158 159 proposalSeal := istanbulCore.PrepareCommittedSeal(header.Hash()) 160 for _, seal := range istanbulExtra.CommittedSeal { 161 _, err := cacheSignatureAddresses(proposalSeal, seal) 162 if err != nil { 163 return errInvalidSignature 164 } 165 } 166 return nil 167 } 168 169 // VerifyHeader checks whether a header conforms to the consensus rules of a 170 // given engine. Verifying the seal may be done optionally here, or explicitly 171 // via the VerifySeal method. 172 func (sb *backend) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { 173 var parent []*types.Header 174 if header.Number.Sign() == 0 { 175 // If current block is genesis, the parent is also genesis 176 parent = append(parent, chain.GetHeaderByNumber(0)) 177 } else { 178 parent = append(parent, chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)) 179 } 180 return sb.verifyHeader(chain, header, parent) 181 } 182 183 // verifyHeader checks whether a header conforms to the consensus rules.The 184 // caller may optionally pass in a batch of parents (ascending order) to avoid 185 // looking those up from the database. This is useful for concurrently verifying 186 // a batch of new headers. 187 func (sb *backend) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 188 if header.Number == nil { 189 return errUnknownBlock 190 } 191 192 // Header verify before/after magma fork 193 if chain.Config().IsMagmaForkEnabled(header.Number) { 194 // the kip71Config used when creating the block number is a previous block config. 195 blockNum := header.Number.Uint64() 196 pset, err := sb.governance.EffectiveParams(blockNum) 197 if err != nil { 198 return err 199 } 200 201 kip71 := pset.ToKIP71Config() 202 if err := misc.VerifyMagmaHeader(parents[len(parents)-1], header, kip71); err != nil { 203 return err 204 } 205 } else if header.BaseFee != nil { 206 return consensus.ErrInvalidBaseFee 207 } 208 209 // Don't waste time checking blocks from the future 210 if header.Time.Cmp(big.NewInt(now().Add(allowedFutureBlockTime).Unix())) > 0 { 211 return consensus.ErrFutureBlock 212 } 213 214 // Ensure that the extra data format is satisfied 215 if _, err := types.ExtractIstanbulExtra(header); err != nil { 216 return errInvalidExtraDataFormat 217 } 218 // Ensure that the block's blockscore is meaningful (may not be correct at this point) 219 if header.BlockScore == nil || header.BlockScore.Cmp(defaultBlockScore) != 0 { 220 return errInvalidBlockScore 221 } 222 223 return sb.verifyCascadingFields(chain, header, parents) 224 } 225 226 // verifyCascadingFields verifies all the header fields that are not standalone, 227 // rather depend on a batch of previous headers. The caller may optionally pass 228 // in a batch of parents (ascending order) to avoid looking those up from the 229 // database. This is useful for concurrently verifying a batch of new headers. 230 func (sb *backend) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 231 // The genesis block is the always valid dead-end 232 number := header.Number.Uint64() 233 if number == 0 { 234 return nil 235 } 236 // Ensure that the block's timestamp isn't too close to it's parent 237 var parent *types.Header 238 if len(parents) > 0 { 239 parent = parents[len(parents)-1] 240 } else { 241 parent = chain.GetHeader(header.ParentHash, number-1) 242 } 243 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 244 return consensus.ErrUnknownAncestor 245 } 246 if parent.Time.Uint64()+sb.config.BlockPeriod > header.Time.Uint64() { 247 return errInvalidTimestamp 248 } 249 if err := sb.verifySigner(chain, header, parents); err != nil { 250 return err 251 } 252 253 // At every epoch governance data will come in block header. Verify it. 254 pset, err := sb.governance.EffectiveParams(number) 255 if err != nil { 256 return err 257 } 258 pendingBlockNum := new(big.Int).Add(chain.CurrentHeader().Number, common.Big1) 259 if number%pset.Epoch() == 0 && len(header.Governance) > 0 && pendingBlockNum.Cmp(header.Number) == 0 { 260 if err := sb.governance.VerifyGovernance(header.Governance); err != nil { 261 return err 262 } 263 } 264 return sb.verifyCommittedSeals(chain, header, parents) 265 } 266 267 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 268 // concurrently. The method returns a quit channel to abort the operations and 269 // a results channel to retrieve the async verifications (the order is that of 270 // the input slice). 271 func (sb *backend) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 272 abort := make(chan struct{}) 273 results := make(chan error, len(headers)) 274 go func() { 275 for i, header := range headers { 276 err := sb.verifyHeader(chain, header, headers[:i]) 277 278 select { 279 case <-abort: 280 return 281 case results <- err: 282 } 283 } 284 }() 285 return abort, results 286 } 287 288 // verifySigner checks whether the signer is in parent's validator set 289 func (sb *backend) verifySigner(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 290 // Verifying the genesis block is not supported 291 number := header.Number.Uint64() 292 if number == 0 { 293 return errUnknownBlock 294 } 295 296 // Retrieve the snapshot needed to verify this header and cache it 297 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents, true) 298 if err != nil { 299 return err 300 } 301 302 // resolve the authorization key and check against signers 303 signer, err := ecrecover(header) 304 if err != nil { 305 return err 306 } 307 308 // Signer should be in the validator set of previous block's extraData. 309 if _, v := snap.ValSet.GetByAddress(signer); v == nil { 310 return errUnauthorized 311 } 312 return nil 313 } 314 315 // verifyCommittedSeals checks whether every committed seal is signed by one of the parent's validators 316 func (sb *backend) verifyCommittedSeals(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 317 number := header.Number.Uint64() 318 // We don't need to verify committed seals in the genesis block 319 if number == 0 { 320 return nil 321 } 322 323 // Retrieve the snapshot needed to verify this header and cache it 324 snap, err := sb.snapshot(chain, number-1, header.ParentHash, parents, true) 325 if err != nil { 326 return err 327 } 328 329 extra, err := types.ExtractIstanbulExtra(header) 330 if err != nil { 331 return err 332 } 333 // The length of Committed seals should be larger than 0 334 if len(extra.CommittedSeal) == 0 { 335 return errEmptyCommittedSeals 336 } 337 338 validators := snap.ValSet.Copy() 339 // Check whether the committed seals are generated by parent's validators 340 validSeal := 0 341 proposalSeal := istanbulCore.PrepareCommittedSeal(header.Hash()) 342 // 1. Get committed seals from current header 343 for _, seal := range extra.CommittedSeal { 344 // 2. Get the original address by seal and parent block hash 345 addr, err := cacheSignatureAddresses(proposalSeal, seal) 346 if err != nil { 347 return errInvalidSignature 348 } 349 // Every validator can have only one seal. If more than one seals are signed by a 350 // validator, the validator cannot be found and errInvalidCommittedSeals is returned. 351 if validators.RemoveValidator(addr) { 352 validSeal += 1 353 } else { 354 return errInvalidCommittedSeals 355 } 356 } 357 358 // The length of validSeal should be larger than number of faulty node + 1 359 if validSeal <= 2*snap.ValSet.F() { 360 return errInvalidCommittedSeals 361 } 362 363 return nil 364 } 365 366 // VerifySeal checks whether the crypto seal on a header is valid according to 367 // the consensus rules of the given engine. 368 func (sb *backend) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 369 // get parent header and ensure the signer is in parent's validator set 370 number := header.Number.Uint64() 371 if number == 0 { 372 return errUnknownBlock 373 } 374 375 // ensure that the blockscore equals to defaultBlockScore 376 if header.BlockScore.Cmp(defaultBlockScore) != 0 { 377 return errInvalidBlockScore 378 } 379 return sb.verifySigner(chain, header, nil) 380 } 381 382 // Prepare initializes the consensus fields of a block header according to the 383 // rules of a particular engine. The changes are executed inline. 384 func (sb *backend) Prepare(chain consensus.ChainReader, header *types.Header) error { 385 // unused fields, force to set to empty 386 header.Rewardbase = sb.rewardbase 387 388 // copy the parent extra data as the header extra data 389 number := header.Number.Uint64() 390 parent := chain.GetHeader(header.ParentHash, number-1) 391 if parent == nil { 392 return consensus.ErrUnknownAncestor 393 } 394 // use the same blockscore for all blocks 395 header.BlockScore = defaultBlockScore 396 397 // Assemble the voting snapshot 398 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil, true) 399 if err != nil { 400 return err 401 } 402 403 // If it reaches the Epoch, governance config will be added to block header 404 pset, err := sb.governance.EffectiveParams(number) 405 if err != nil { 406 return err 407 } 408 if number%pset.Epoch() == 0 { 409 if g := sb.governance.GetGovernanceChange(); g != nil { 410 if data, err := json.Marshal(g); err != nil { 411 logger.Error("Failed to encode governance changes!! Possible configuration mismatch!! ") 412 } else { 413 if header.Governance, err = rlp.EncodeToBytes(data); err != nil { 414 logger.Error("Failed to encode governance data for the header", "num", number) 415 } else { 416 logger.Info("Put governanceData", "num", number, "data", hex.EncodeToString(header.Governance)) 417 } 418 } 419 } 420 } 421 422 // if there is a vote to attach, attach it to the header 423 header.Vote = sb.governance.GetEncodedVote(sb.address, number) 424 if len(header.Vote) > 0 { 425 logger.Info("Put voteData", "num", number, "data", hex.EncodeToString(header.Vote)) 426 } 427 428 // add validators (council list) in snapshot to extraData's validators section 429 extra, err := prepareExtra(header, snap.validators()) 430 if err != nil { 431 return err 432 } 433 header.Extra = extra 434 435 // set header's timestamp 436 header.Time = new(big.Int).Add(parent.Time, new(big.Int).SetUint64(sb.config.BlockPeriod)) 437 header.TimeFoS = parent.TimeFoS 438 if header.Time.Int64() < time.Now().Unix() { 439 t := time.Now() 440 header.Time = big.NewInt(t.Unix()) 441 header.TimeFoS = uint8((t.UnixNano() / 1000 / 1000 / 10) % 100) 442 } 443 return nil 444 } 445 446 // Finalize runs any post-transaction state modifications (e.g. block rewards) 447 // and assembles the final block. 448 // 449 // Note, the block header and state database might be updated to reflect any 450 // consensus rules that happen at finalization (e.g. block rewards). 451 func (sb *backend) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 452 receipts []*types.Receipt, 453 ) (*types.Block, error) { 454 // We can assure that if the magma hard forked block should have the field of base fee 455 if chain.Config().IsMagmaForkEnabled(header.Number) { 456 if header.BaseFee == nil { 457 logger.Error("Magma hard forked block should have baseFee", "blockNum", header.Number.Uint64()) 458 return nil, errors.New("Invalid Magma block without baseFee") 459 } 460 } else if header.BaseFee != nil { 461 logger.Error("A block before Magma hardfork shouldn't have baseFee", "blockNum", header.Number.Uint64()) 462 return nil, consensus.ErrInvalidBaseFee 463 } 464 465 var rewardSpec *reward.RewardSpec 466 467 rules := chain.Config().Rules(header.Number) 468 pset, err := sb.governance.EffectiveParams(header.Number.Uint64()) 469 if err != nil { 470 return nil, err 471 } 472 473 // If sb.chain is nil, it means backend is not initialized yet. 474 if sb.chain != nil && !reward.IsRewardSimple(pset) { 475 // TODO-Klaytn Let's redesign below logic and remove dependency between block reward and istanbul consensus. 476 477 lastHeader := chain.CurrentHeader() 478 valSet := sb.getValidators(lastHeader.Number.Uint64(), lastHeader.Hash()) 479 480 // Determine and update Rewardbase when mining. When mining, state root is not yet determined and will be determined at the end of this Finalize below. 481 if common.EmptyHash(header.Root) { 482 var logMsg string 483 _, nodeValidator := valSet.GetByAddress(sb.address) 484 if nodeValidator == nil || (nodeValidator.RewardAddress() == common.Address{}) { 485 logMsg = "No reward address for nodeValidator. Use node's rewardbase." 486 } else { 487 // use reward address of current node. 488 // only a block made by proposer will be accepted. However, due to round change any node can be the proposer of a block. 489 // so need to write reward address of current node to receive reward when it becomes proposer. 490 // if current node does not become proposer, the block will be abandoned 491 header.Rewardbase = nodeValidator.RewardAddress() 492 logMsg = "Use reward address for nodeValidator." 493 } 494 logger.Trace(logMsg, "header.Number", header.Number.Uint64(), "node address", sb.address, "rewardbase", header.Rewardbase) 495 } 496 497 rewardSpec, err = reward.CalcDeferredReward(header, rules, pset) 498 } else { 499 rewardSpec, err = reward.CalcDeferredRewardSimple(header, rules, pset) 500 } 501 502 if err != nil { 503 return nil, err 504 } 505 506 reward.DistributeBlockReward(state, rewardSpec.Rewards) 507 508 // Only on the KIP-103 hardfork block, the following logic should be executed 509 if chain.Config().IsKIP103ForkBlock(header.Number) { 510 // RebalanceTreasury can modify the global state (state), 511 // so the existing state db should be used to apply the rebalancing result. 512 c := &Kip103ContractCaller{state, chain, header} 513 result, err := RebalanceTreasury(state, chain, header, c) 514 if err != nil { 515 logger.Error("failed to execute treasury rebalancing (KIP-103). State not changed", "err", err) 516 } else { 517 memo, err := json.Marshal(result) 518 if err != nil { 519 logger.Warn("failed to marshal KIP-103 result", "err", err, "result", result) 520 } 521 logger.Info("successfully executed treasury rebalancing (KIP-103)", "memo", string(memo)) 522 } 523 } 524 header.Root = state.IntermediateRoot(true) 525 526 // Assemble and return the final block for sealing 527 return types.NewBlock(header, txs, receipts), nil 528 } 529 530 // Seal generates a new block for the given input block with the local miner's 531 // seal place on top. 532 func (sb *backend) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { 533 // update the block header timestamp and signature and propose the block to core engine 534 header := block.Header() 535 number := header.Number.Uint64() 536 537 // Bail out if we're unauthorized to sign a block 538 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil, true) 539 if err != nil { 540 return nil, err 541 } 542 if _, v := snap.ValSet.GetByAddress(sb.address); v == nil { 543 return nil, errUnauthorized 544 } 545 546 parent := chain.GetHeader(header.ParentHash, number-1) 547 if parent == nil { 548 return nil, consensus.ErrUnknownAncestor 549 } 550 block, err = sb.updateBlock(parent, block) 551 if err != nil { 552 return nil, err 553 } 554 555 // wait for the timestamp of header, use this to adjust the block period 556 delay := time.Unix(block.Header().Time.Int64(), 0).Sub(now()) 557 select { 558 case <-time.After(delay): 559 case <-stop: 560 return nil, nil 561 } 562 563 // get the proposed block hash and clear it if the seal() is completed. 564 sb.sealMu.Lock() 565 sb.proposedBlockHash = block.Hash() 566 clear := func() { 567 sb.proposedBlockHash = common.Hash{} 568 sb.sealMu.Unlock() 569 } 570 defer clear() 571 572 // post block into Istanbul engine 573 go sb.EventMux().Post(istanbul.RequestEvent{ 574 Proposal: block, 575 }) 576 577 for { 578 select { 579 case result := <-sb.commitCh: 580 if result == nil { 581 return nil, nil 582 } 583 // if the block hash and the hash from channel are the same, 584 // return the result. Otherwise, keep waiting the next hash. 585 block = types.SetRoundToBlock(block, result.Round) 586 if block.Hash() == result.Block.Hash() { 587 return result.Block, nil 588 } 589 case <-stop: 590 return nil, nil 591 } 592 } 593 } 594 595 // update timestamp and signature of the block based on its number of transactions 596 func (sb *backend) updateBlock(parent *types.Header, block *types.Block) (*types.Block, error) { 597 header := block.Header() 598 // sign the hash 599 seal, err := sb.Sign(sigHash(header).Bytes()) 600 if err != nil { 601 return nil, err 602 } 603 604 err = writeSeal(header, seal) 605 if err != nil { 606 return nil, err 607 } 608 609 return block.WithSeal(header), nil 610 } 611 612 func (sb *backend) CalcBlockScore(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 613 return big.NewInt(0) 614 } 615 616 // APIs returns the RPC APIs this consensus engine provides. 617 func (sb *backend) APIs(chain consensus.ChainReader) []rpc.API { 618 return []rpc.API{ 619 { 620 Namespace: "istanbul", 621 Version: "1.0", 622 Service: &API{chain: chain, istanbul: sb}, 623 Public: true, 624 }, { 625 Namespace: "klay", 626 Version: "1.0", 627 Service: &APIExtension{chain: chain, istanbul: sb}, 628 Public: true, 629 }, 630 } 631 } 632 633 // SetChain sets chain of the Istanbul backend 634 func (sb *backend) SetChain(chain consensus.ChainReader) { 635 sb.chain = chain 636 } 637 638 // Start implements consensus.Istanbul.Start 639 func (sb *backend) Start(chain consensus.ChainReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error { 640 sb.coreMu.Lock() 641 defer sb.coreMu.Unlock() 642 if sb.coreStarted { 643 return istanbul.ErrStartedEngine 644 } 645 646 // clear previous data 647 sb.proposedBlockHash = common.Hash{} 648 if sb.commitCh != nil { 649 close(sb.commitCh) 650 } 651 sb.commitCh = make(chan *types.Result, 1) 652 653 sb.SetChain(chain) 654 sb.currentBlock = currentBlock 655 sb.hasBadBlock = hasBadBlock 656 657 if err := sb.core.Start(); err != nil { 658 return err 659 } 660 661 sb.coreStarted = true 662 return nil 663 } 664 665 // Stop implements consensus.Istanbul.Stop 666 func (sb *backend) Stop() error { 667 sb.coreMu.Lock() 668 defer sb.coreMu.Unlock() 669 if !sb.coreStarted { 670 return istanbul.ErrStoppedEngine 671 } 672 if err := sb.core.Stop(); err != nil { 673 return err 674 } 675 sb.coreStarted = false 676 return nil 677 } 678 679 // initSnapshot initializes and stores a new Snapshot. 680 func (sb *backend) initSnapshot(chain consensus.ChainReader) (*Snapshot, error) { 681 genesis := chain.GetHeaderByNumber(0) 682 if err := sb.VerifyHeader(chain, genesis, false); err != nil { 683 return nil, err 684 } 685 istanbulExtra, err := types.ExtractIstanbulExtra(genesis) 686 if err != nil { 687 return nil, err 688 } 689 690 pset, err := sb.governance.EffectiveParams(0) 691 if err != nil { 692 return nil, err 693 } 694 valSet := validator.NewValidatorSet(istanbulExtra.Validators, nil, 695 istanbul.ProposerPolicy(pset.Policy()), 696 pset.CommitteeSize(), chain) 697 snap := newSnapshot(sb.governance, 0, genesis.Hash(), valSet, chain.Config()) 698 699 if err := snap.store(sb.db); err != nil { 700 return nil, err 701 } 702 logger.Trace("Stored genesis voting snapshot to disk") 703 return snap, nil 704 } 705 706 // getPrevHeaderAndUpdateParents returns previous header to find stored Snapshot object and drops the last element of the parents parameter. 707 func getPrevHeaderAndUpdateParents(chain consensus.ChainReader, number uint64, hash common.Hash, parents *[]*types.Header) *types.Header { 708 var header *types.Header 709 if len(*parents) > 0 { 710 // If we have explicit parents, pick from there (enforced) 711 header = (*parents)[len(*parents)-1] 712 if header.Hash() != hash || header.Number.Uint64() != number { 713 return nil 714 } 715 *parents = (*parents)[:len(*parents)-1] 716 } else { 717 // No explicit parents (or no more left), reach out to the database 718 header = chain.GetHeader(hash, number) 719 if header == nil { 720 return nil 721 } 722 } 723 return header 724 } 725 726 // CreateSnapshot does not return a snapshot but creates a new snapshot at a given point in time. 727 func (sb *backend) CreateSnapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header) error { 728 if _, err := sb.snapshot(chain, number, hash, parents, true); err != nil { 729 return err 730 } 731 if err := sb.governance.UpdateParams(number); err != nil { 732 return err 733 } 734 return nil 735 } 736 737 // GetConsensusInfo returns consensus information regarding the given block number. 738 func (sb *backend) GetConsensusInfo(block *types.Block) (consensus.ConsensusInfo, error) { 739 blockNumber := block.NumberU64() 740 if blockNumber == 0 { 741 return consensus.ConsensusInfo{}, nil 742 } 743 744 round := block.Header().Round() 745 view := &istanbul.View{ 746 Sequence: new(big.Int).Set(block.Number()), 747 Round: new(big.Int).SetInt64(int64(round)), 748 } 749 750 // get the proposer of this block. 751 proposer, err := ecrecover(block.Header()) 752 if err != nil { 753 return consensus.ConsensusInfo{}, err 754 } 755 756 // get the snapshot of the previous block. 757 parentHash := block.ParentHash() 758 snap, err := sb.snapshot(sb.chain, blockNumber-1, parentHash, nil, false) 759 if err != nil { 760 logger.Error("Failed to get snapshot.", "hash", snap.Hash, "err", err) 761 return consensus.ConsensusInfo{}, errInternalError 762 } 763 764 // get origin proposer at 0 round. 765 originProposer := common.Address{} 766 lastProposer := sb.GetProposer(blockNumber - 1) 767 768 newValSet := snap.ValSet.Copy() 769 newValSet.CalcProposer(lastProposer, 0) 770 originProposer = newValSet.GetProposer().Address() 771 772 // get the committee list of this block at the view (blockNumber, round) 773 committee := snap.ValSet.SubListWithProposer(parentHash, proposer, view) 774 committeeAddrs := make([]common.Address, len(committee)) 775 for i, v := range committee { 776 committeeAddrs[i] = v.Address() 777 } 778 779 // verify the committee list of the block using istanbul 780 //proposalSeal := istanbulCore.PrepareCommittedSeal(block.Hash()) 781 //extra, err := types.ExtractIstanbulExtra(block.Header()) 782 //istanbulAddrs := make([]common.Address, len(committeeAddrs)) 783 //for i, seal := range extra.CommittedSeal { 784 // addr, err := istanbul.GetSignatureAddress(proposalSeal, seal) 785 // istanbulAddrs[i] = addr 786 // if err != nil { 787 // return proposer, []common.Address{}, err 788 // } 789 // 790 // var found bool = false 791 // for _, v := range committeeAddrs { 792 // if addr == v { 793 // found = true 794 // break 795 // } 796 // } 797 // if found == false { 798 // logger.Trace("validator is different!", "snap", committeeAddrs, "istanbul", istanbulAddrs) 799 // return proposer, committeeAddrs, errors.New("validator set is different from Istanbul engine!!") 800 // } 801 //} 802 803 cInfo := consensus.ConsensusInfo{ 804 Proposer: proposer, 805 OriginProposer: originProposer, 806 Committee: committeeAddrs, 807 Round: round, 808 } 809 810 return cInfo, nil 811 } 812 813 // snapshot retrieves the authorization snapshot at a given point in time. 814 func (sb *backend) snapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header, writable bool) (*Snapshot, error) { 815 // Search for a snapshot in memory or on disk for checkpoints 816 var ( 817 headers []*types.Header 818 snap *Snapshot 819 ) 820 821 for snap == nil { 822 // If an in-memory snapshot was found, use that 823 if s, ok := sb.recents.Get(hash); ok { 824 snap = s.(*Snapshot) 825 break 826 } 827 // If an on-disk checkpoint snapshot can be found, use that 828 if number%checkpointInterval == 0 { 829 if s, err := loadSnapshot(sb.db, hash); err == nil { 830 logger.Trace("Loaded voting snapshot form disk", "number", number, "hash", hash) 831 snap = s 832 break 833 } 834 } 835 // If we're at block zero, make a snapshot 836 if number == 0 { 837 var err error 838 if snap, err = sb.initSnapshot(chain); err != nil { 839 return nil, err 840 } 841 break 842 } 843 // No snapshot for this header, gather the header and move backward 844 if header := getPrevHeaderAndUpdateParents(chain, number, hash, &parents); header == nil { 845 return nil, consensus.ErrUnknownAncestor 846 } else { 847 headers = append(headers, header) 848 number, hash = number-1, header.ParentHash 849 } 850 } 851 // Previous snapshot found, apply any pending headers on top of it 852 for i := 0; i < len(headers)/2; i++ { 853 headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i] 854 } 855 pset, err := sb.governance.EffectiveParams(number) 856 if err != nil { 857 return nil, err 858 } 859 snap, err = snap.apply(headers, sb.governance, sb.address, pset.Policy(), chain, writable) 860 if err != nil { 861 return nil, err 862 } 863 864 // If we've generated a new checkpoint snapshot, save to disk 865 if writable && snap.Number%checkpointInterval == 0 && len(headers) > 0 { 866 if sb.governance.CanWriteGovernanceState(snap.Number) { 867 sb.governance.WriteGovernanceState(snap.Number, true) 868 } 869 if err = snap.store(sb.db); err != nil { 870 return nil, err 871 } 872 logger.Trace("Stored voting snapshot to disk", "number", snap.Number, "hash", snap.Hash) 873 } 874 875 sb.recents.Add(snap.Hash, snap) 876 return snap, err 877 } 878 879 // FIXME: Need to update this for Istanbul 880 // sigHash returns the hash which is used as input for the Istanbul 881 // signing. It is the hash of the entire header apart from the 65 byte signature 882 // contained at the end of the extra data. 883 // 884 // Note, the method requires the extra data to be at least 65 bytes, otherwise it 885 // panics. This is done to avoid accidentally using both forms (signature present 886 // or not), which could be abused to produce different hashes for the same header. 887 func sigHash(header *types.Header) (hash common.Hash) { 888 hasher := sha3.NewKeccak256() 889 890 // Clean seal is required for calculating proposer seal. 891 rlp.Encode(hasher, types.IstanbulFilteredHeader(header, false)) 892 hasher.Sum(hash[:0]) 893 return hash 894 } 895 896 // ecrecover extracts the Klaytn account address from a signed header. 897 func ecrecover(header *types.Header) (common.Address, error) { 898 // Retrieve the signature from the header extra-data 899 istanbulExtra, err := types.ExtractIstanbulExtra(header) 900 if err != nil { 901 return common.Address{}, err 902 } 903 addr, err := cacheSignatureAddresses(sigHash(header).Bytes(), istanbulExtra.Seal) 904 if err != nil { 905 return addr, err 906 } 907 908 return addr, nil 909 } 910 911 // prepareExtra returns a extra-data of the given header and validators 912 func prepareExtra(header *types.Header, vals []common.Address) ([]byte, error) { 913 var buf bytes.Buffer 914 915 // compensate the lack bytes if header.Extra is not enough IstanbulExtraVanity bytes. 916 if len(header.Extra) < types.IstanbulExtraVanity { 917 header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity-len(header.Extra))...) 918 } 919 buf.Write(header.Extra[:types.IstanbulExtraVanity]) 920 921 ist := &types.IstanbulExtra{ 922 Validators: vals, 923 Seal: []byte{}, 924 CommittedSeal: [][]byte{}, 925 } 926 927 payload, err := rlp.EncodeToBytes(&ist) 928 if err != nil { 929 return nil, err 930 } 931 932 return append(buf.Bytes(), payload...), nil 933 } 934 935 // writeSeal writes the extra-data field of the given header with the given seals. 936 // suggest to rename to writeSeal. 937 func writeSeal(h *types.Header, seal []byte) error { 938 if len(seal)%types.IstanbulExtraSeal != 0 { 939 return errInvalidSignature 940 } 941 942 istanbulExtra, err := types.ExtractIstanbulExtra(h) 943 if err != nil { 944 return err 945 } 946 947 istanbulExtra.Seal = seal 948 payload, err := rlp.EncodeToBytes(&istanbulExtra) 949 if err != nil { 950 return err 951 } 952 953 h.Extra = append(h.Extra[:types.IstanbulExtraVanity], payload...) 954 return nil 955 } 956 957 // writeCommittedSeals writes the extra-data field of a block header with given committed seals. 958 func writeCommittedSeals(h *types.Header, committedSeals [][]byte) error { 959 if len(committedSeals) == 0 { 960 return errInvalidCommittedSeals 961 } 962 963 for _, seal := range committedSeals { 964 if len(seal) != types.IstanbulExtraSeal { 965 return errInvalidCommittedSeals 966 } 967 } 968 969 istanbulExtra, err := types.ExtractIstanbulExtra(h) 970 if err != nil { 971 return err 972 } 973 974 istanbulExtra.CommittedSeal = make([][]byte, len(committedSeals)) 975 copy(istanbulExtra.CommittedSeal, committedSeals) 976 977 payload, err := rlp.EncodeToBytes(&istanbulExtra) 978 if err != nil { 979 return err 980 } 981 982 h.Extra = append(h.Extra[:types.IstanbulExtraVanity], payload...) 983 return nil 984 }