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