github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/istanbul/backend/backend.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 "errors" 21 "fmt" 22 blscrypto "github.com/ethereum/go-ethereum/crypto/bls" 23 "math/big" 24 "sync" 25 "time" 26 27 "github.com/ethereum/go-ethereum/accounts" 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/consensus" 30 "github.com/ethereum/go-ethereum/consensus/istanbul" 31 "github.com/ethereum/go-ethereum/consensus/istanbul/backend/internal/enodes" 32 istanbulCore "github.com/ethereum/go-ethereum/consensus/istanbul/core" 33 "github.com/ethereum/go-ethereum/consensus/istanbul/validator" 34 "github.com/ethereum/go-ethereum/contract_comm/election" 35 comm_errors "github.com/ethereum/go-ethereum/contract_comm/errors" 36 "github.com/ethereum/go-ethereum/contract_comm/random" 37 "github.com/ethereum/go-ethereum/contract_comm/validators" 38 "github.com/ethereum/go-ethereum/core" 39 "github.com/ethereum/go-ethereum/core/state" 40 "github.com/ethereum/go-ethereum/core/types" 41 "github.com/ethereum/go-ethereum/crypto" 42 "github.com/ethereum/go-ethereum/ethdb" 43 "github.com/ethereum/go-ethereum/event" 44 "github.com/ethereum/go-ethereum/log" 45 "github.com/ethereum/go-ethereum/metrics" 46 "github.com/ethereum/go-ethereum/p2p" 47 "github.com/ethereum/go-ethereum/p2p/enode" 48 "github.com/ethereum/go-ethereum/rlp" 49 lru "github.com/hashicorp/golang-lru" 50 ) 51 52 const ( 53 // fetcherID is the ID indicates the block is from Istanbul engine 54 fetcherID = "istanbul" 55 ) 56 57 var ( 58 // errInvalidSigningFn is returned when the consensus signing function is invalid. 59 errInvalidSigningFn = errors.New("invalid signing function for istanbul messages") 60 61 // errProxyAlreadySet is returned if a user tries to add a proxy that is already set. 62 // TODO - When we support multiple sentries per validator, this error will become irrelevant. 63 errProxyAlreadySet = errors.New("proxy already set") 64 65 // errNoProxyConnection is returned when a proxied validator is not connected to a proxy 66 errNoProxyConnection = errors.New("proxied validator not connected to a proxy") 67 68 // errNoBlockHeader is returned when the requested block header could not be found. 69 errNoBlockHeader = errors.New("failed to retrieve block header") 70 71 // errOldAnnounceMessage is returned when the received announce message's block number is earlier 72 // than a previous received message 73 errOldAnnounceMessage = errors.New("old announce message") 74 ) 75 76 // Entries for the recent announce messages 77 type AnnounceGossipTimestamp struct { 78 enodeURLHash common.Hash 79 destAddressesHash common.Hash 80 timestamp time.Time 81 } 82 83 // Information about the proxy for a proxied validator 84 type proxyInfo struct { 85 node *enode.Node // Enode for the internal network interface 86 externalNode *enode.Node // Enode for the external network interface 87 peer consensus.Peer // Connected proxy peer. Is nil if this node is not connected to the proxy 88 } 89 90 // New creates an Ethereum backend for Istanbul core engine. 91 func New(config *istanbul.Config, db ethdb.Database) consensus.Istanbul { 92 // Allocate the snapshot caches and create the engine 93 logger := log.New() 94 recentSnapshots, err := lru.NewARC(inmemorySnapshots) 95 if err != nil { 96 logger.Crit("Failed to create recent snapshots cache", "err", err) 97 } 98 recentMessages, err := lru.NewARC(inmemoryPeers) 99 if err != nil { 100 logger.Crit("Failed to create recent messages cache", "err", err) 101 } 102 knownMessages, err := lru.NewARC(inmemoryMessages) 103 if err != nil { 104 logger.Crit("Failed to create known messages cache", "err", err) 105 } 106 backend := &Backend{ 107 config: config, 108 istanbulEventMux: new(event.TypeMux), 109 logger: logger, 110 db: db, 111 commitCh: make(chan *types.Block, 1), 112 recentSnapshots: recentSnapshots, 113 coreStarted: false, 114 recentMessages: recentMessages, 115 knownMessages: knownMessages, 116 announceWg: new(sync.WaitGroup), 117 announceQuit: make(chan struct{}), 118 lastAnnounceGossiped: make(map[common.Address]*AnnounceGossipTimestamp), 119 valEnodesShareWg: new(sync.WaitGroup), 120 valEnodesShareQuit: make(chan struct{}), 121 finalizationTimer: metrics.NewRegisteredTimer("consensus/istanbul/backend/finalize", nil), 122 rewardDistributionTimer: metrics.NewRegisteredTimer("consensus/istanbul/backend/rewards", nil), 123 } 124 backend.core = istanbulCore.New(backend, backend.config) 125 126 backend.logger = istanbul.NewIstLogger( 127 func() *big.Int { 128 if backend.core != nil && backend.core.CurrentView() != nil { 129 return backend.core.CurrentView().Round 130 } 131 return common.Big0 132 }, 133 ) 134 135 vph := &validatorPeerHandler{sb: backend} 136 table, err := enodes.OpenValidatorEnodeDB(config.ValidatorEnodeDBPath, vph) 137 if err != nil { 138 logger.Crit("Can't open ValidatorEnodeDB", "err", err, "dbpath", config.ValidatorEnodeDBPath) 139 } 140 backend.valEnodeTable = table 141 142 return backend 143 } 144 145 // ---------------------------------------------------------------------------- 146 147 type Backend struct { 148 config *istanbul.Config 149 istanbulEventMux *event.TypeMux 150 151 address common.Address // Ethereum address of the signing key 152 signFn istanbul.SignerFn // Signer function to authorize hashes with 153 signHashBLSFn istanbul.BLSSignerFn // Signer function to authorize hashes using BLS with 154 signMessageBLSFn istanbul.MessageSignerFn // Signer function to authorize messages using BLS with 155 signFnMu sync.RWMutex // Protects the signer fields 156 157 core istanbulCore.Engine 158 logger log.Logger 159 db ethdb.Database 160 chain consensus.ChainReader 161 currentBlock func() *types.Block 162 hasBadBlock func(hash common.Hash) bool 163 stateAt func(hash common.Hash) (*state.StateDB, error) 164 165 processBlock func(block *types.Block, statedb *state.StateDB) (types.Receipts, []*types.Log, uint64, error) 166 validateState func(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error 167 168 // the channels for istanbul engine notifications 169 commitCh chan *types.Block 170 proposedBlockHash common.Hash 171 sealMu sync.Mutex 172 coreStarted bool 173 coreMu sync.RWMutex 174 175 // Snapshots for recent blocks to speed up reorgs 176 recentSnapshots *lru.ARCCache 177 178 // event subscription for ChainHeadEvent event 179 broadcaster consensus.Broadcaster 180 181 // interface to the p2p server 182 p2pserver consensus.P2PServer 183 184 recentMessages *lru.ARCCache // the cache of peer's messages 185 knownMessages *lru.ARCCache // the cache of self messages 186 187 lastAnnounceGossiped map[common.Address]*AnnounceGossipTimestamp 188 lastAnnounceGossipedMu sync.RWMutex 189 190 valEnodeTable *enodes.ValidatorEnodeDB 191 192 announceWg *sync.WaitGroup 193 announceQuit chan struct{} 194 195 valEnodesShareWg *sync.WaitGroup 196 valEnodesShareQuit chan struct{} 197 198 proxyNode *proxyInfo 199 200 // Right now, we assume that there is at most one proxied peer for a proxy 201 proxiedPeer consensus.Peer 202 203 newEpochCh chan struct{} 204 205 delegateSignFeed event.Feed 206 delegateSignScope event.SubscriptionScope 207 208 // Metric timer used to record block finalization times. 209 finalizationTimer metrics.Timer 210 // Metric timer used to record epoch reward distribution times. 211 rewardDistributionTimer metrics.Timer 212 } 213 214 func (sb *Backend) IsProxy() bool { 215 return sb.proxiedPeer != nil 216 } 217 218 func (sb *Backend) IsProxiedValidator() bool { 219 return sb.proxyNode != nil && sb.proxyNode.peer != nil 220 } 221 222 // SendDelegateSignMsgToProxy sends an istanbulDelegateSign message to a proxy 223 // if one exists 224 func (sb *Backend) SendDelegateSignMsgToProxy(msg []byte) error { 225 if !sb.IsProxiedValidator() { 226 err := errors.New("No Proxy found") 227 sb.logger.Error("SendDelegateSignMsgToProxy failed", "err", err) 228 return err 229 } 230 return sb.proxyNode.peer.Send(istanbulDelegateSign, msg) 231 } 232 233 // SendDelegateSignMsgToProxiedValidator sends an istanbulDelegateSign message to a 234 // proxied validator if one exists 235 func (sb *Backend) SendDelegateSignMsgToProxiedValidator(msg []byte) error { 236 if !sb.IsProxy() { 237 err := errors.New("No Proxied Validator found") 238 sb.logger.Error("SendDelegateSignMsgToProxiedValidator failed", "err", err) 239 return err 240 } 241 return sb.proxiedPeer.Send(istanbulDelegateSign, msg) 242 } 243 244 // Authorize implements istanbul.Backend.Authorize 245 func (sb *Backend) Authorize(address common.Address, signFn istanbul.SignerFn, signHashBLSFn istanbul.BLSSignerFn, signMessageBLSFn istanbul.MessageSignerFn) { 246 sb.signFnMu.Lock() 247 defer sb.signFnMu.Unlock() 248 249 sb.address = address 250 sb.signFn = signFn 251 sb.signHashBLSFn = signHashBLSFn 252 sb.signMessageBLSFn = signMessageBLSFn 253 sb.core.SetAddress(address) 254 } 255 256 // Address implements istanbul.Backend.Address 257 func (sb *Backend) Address() common.Address { 258 return sb.address 259 } 260 261 // Close the backend 262 func (sb *Backend) Close() error { 263 sb.delegateSignScope.Close() 264 return sb.valEnodeTable.Close() 265 } 266 267 // Validators implements istanbul.Backend.Validators 268 func (sb *Backend) Validators(proposal istanbul.Proposal) istanbul.ValidatorSet { 269 return sb.getOrderedValidators(proposal.Number().Uint64(), proposal.Hash()) 270 } 271 272 // ParentBlockValidators implements istanbul.Backend.ParentBlockValidators 273 func (sb *Backend) ParentBlockValidators(proposal istanbul.Proposal) istanbul.ValidatorSet { 274 return sb.getOrderedValidators(proposal.Number().Uint64()-1, proposal.ParentHash()) 275 } 276 277 func (sb *Backend) NextBlockValidators(proposal istanbul.Proposal) (istanbul.ValidatorSet, error) { 278 istExtra, err := types.ExtractIstanbulExtra(proposal.Header()) 279 if err != nil { 280 return nil, err 281 } 282 283 // There was no change 284 if len(istExtra.AddedValidators) == 0 && istExtra.RemovedValidators.BitLen() == 0 { 285 return sb.ParentBlockValidators(proposal), nil 286 } 287 288 snap, err := sb.snapshot(sb.chain, proposal.Number().Uint64()-1, common.Hash{}, nil) 289 if err != nil { 290 return nil, err 291 } 292 snap = snap.copy() 293 294 addedValidators, err := istanbul.CombineIstanbulExtraToValidatorData(istExtra.AddedValidators, istExtra.AddedValidatorsPublicKeys) 295 if err != nil { 296 return nil, err 297 } 298 299 if !snap.ValSet.RemoveValidators(istExtra.RemovedValidators) { 300 return nil, fmt.Errorf("could not obtain next block validators: failed at remove validators") 301 } 302 if !snap.ValSet.AddValidators(addedValidators) { 303 return nil, fmt.Errorf("could not obtain next block validators: failed at add validators") 304 } 305 306 return snap.ValSet, nil 307 } 308 309 func (sb *Backend) GetValidators(blockNumber *big.Int, headerHash common.Hash) []istanbul.Validator { 310 validatorSet := sb.getValidators(blockNumber.Uint64(), headerHash) 311 return validatorSet.List() 312 } 313 314 // This function will return the peers with the addresses in the "destAddresses" parameter. 315 // If this is a proxied validator, then it will return the proxy. 316 func (sb *Backend) getPeersForMessage(destAddresses []common.Address) map[enode.ID]consensus.Peer { 317 if sb.config.Proxied { 318 if sb.proxyNode != nil && sb.proxyNode.peer != nil { 319 returnMap := make(map[enode.ID]consensus.Peer) 320 returnMap[sb.proxyNode.peer.Node().ID()] = sb.proxyNode.peer 321 322 return returnMap 323 } else { 324 return nil 325 } 326 } else { 327 var targets map[enode.ID]bool = nil 328 329 if destAddresses != nil { 330 targets = make(map[enode.ID]bool) 331 for _, addr := range destAddresses { 332 if valNode, err := sb.valEnodeTable.GetNodeFromAddress(addr); valNode != nil && err == nil { 333 targets[valNode.ID()] = true 334 } 335 } 336 } 337 return sb.broadcaster.FindPeers(targets, p2p.AnyPurpose) 338 } 339 } 340 341 // Broadcast implements istanbul.Backend.BroadcastConsensusMsg 342 func (sb *Backend) BroadcastConsensusMsg(destAddresses []common.Address, payload []byte) error { 343 sb.logger.Trace("Broadcasting an istanbul message", "destAddresses", common.ConvertToStringSlice(destAddresses)) 344 345 // send to others 346 if err := sb.Gossip(destAddresses, payload, istanbulConsensusMsg, false); err != nil { 347 return err 348 } 349 350 // send to self 351 msg := istanbul.MessageEvent{ 352 Payload: payload, 353 } 354 go sb.istanbulEventMux.Post(msg) 355 return nil 356 } 357 358 // Gossip implements istanbul.Backend.Gossip 359 func (sb *Backend) Gossip(destAddresses []common.Address, payload []byte, ethMsgCode uint64, ignoreCache bool) error { 360 // If this is a proxied validator and it wants to send a consensus message, 361 // wrap the consensus message in a forward message. 362 if sb.config.Proxied && ethMsgCode == istanbulConsensusMsg { 363 var err error 364 365 fwdMessage := &istanbul.ForwardMessage{DestAddresses: destAddresses, Msg: payload} 366 fwdMsgBytes, err := rlp.EncodeToBytes(fwdMessage) 367 if err != nil { 368 sb.logger.Error("Failed to encode", "fwdMessage", fwdMessage) 369 return err 370 } 371 372 // Note that we are not signing message. The message that is being wrapped is already signed. 373 msg := istanbul.Message{Code: istanbulFwdMsg, Msg: fwdMsgBytes, Address: sb.Address()} 374 payload, err = msg.Payload() 375 if err != nil { 376 return err 377 } 378 379 ethMsgCode = istanbulFwdMsg 380 } 381 382 peers := sb.getPeersForMessage(destAddresses) 383 384 var hash common.Hash 385 if !ignoreCache { 386 hash = istanbul.RLPHash(payload) 387 sb.knownMessages.Add(hash, true) 388 } 389 390 if len(peers) > 0 { 391 for nodeID, p := range peers { 392 if !ignoreCache { 393 ms, ok := sb.recentMessages.Get(nodeID) 394 var m *lru.ARCCache 395 if ok { 396 m, _ = ms.(*lru.ARCCache) 397 if _, k := m.Get(hash); k { 398 // This peer had this event, skip it 399 continue 400 } 401 } else { 402 m, _ = lru.NewARC(inmemoryMessages) 403 } 404 405 m.Add(hash, true) 406 sb.recentMessages.Add(nodeID, m) 407 } 408 sb.logger.Trace("Sending istanbul message to peer", "msg_code", ethMsgCode, "nodeID", nodeID) 409 410 go p.Send(ethMsgCode, payload) 411 } 412 } 413 return nil 414 } 415 416 // Commit implements istanbul.Backend.Commit 417 func (sb *Backend) Commit(proposal istanbul.Proposal, aggregatedSeal types.IstanbulAggregatedSeal, aggregatedEpochValidatorSetSeal types.IstanbulEpochValidatorSetSeal) error { 418 // Check if the proposal is a valid block 419 block := &types.Block{} 420 block, ok := proposal.(*types.Block) 421 if !ok { 422 sb.logger.Error("Invalid proposal, %v", proposal) 423 return errInvalidProposal 424 } 425 426 h := block.Header() 427 // Append seals into extra-data 428 err := writeAggregatedSeal(h, aggregatedSeal, false) 429 if err != nil { 430 return err 431 } 432 // update block's header 433 block = block.WithSeal(h) 434 block = block.WithEpochSnarkData(&types.EpochSnarkData{ 435 Signature: aggregatedEpochValidatorSetSeal.Signature, 436 }) 437 438 sb.logger.Info("Committed", "address", sb.Address(), "round", aggregatedSeal.Round.Uint64(), "hash", proposal.Hash(), "number", proposal.Number().Uint64()) 439 // - if the proposed and committed blocks are the same, send the proposed hash 440 // to commit channel, which is being watched inside the engine.Seal() function. 441 // - otherwise, we try to insert the block. 442 // -- if success, the ChainHeadEvent event will be broadcasted, try to build 443 // the next block and the previous Seal() will be stopped. 444 // -- otherwise, a error will be returned and a round change event will be fired. 445 if sb.proposedBlockHash == block.Hash() { 446 // feed block hash to Seal() and wait the Seal() result 447 sb.commitCh <- block 448 return nil 449 } 450 451 if sb.broadcaster != nil { 452 sb.broadcaster.Enqueue(fetcherID, block) 453 } 454 return nil 455 } 456 457 // EventMux implements istanbul.Backend.EventMux 458 func (sb *Backend) EventMux() *event.TypeMux { 459 return sb.istanbulEventMux 460 } 461 462 // Verify implements istanbul.Backend.Verify 463 func (sb *Backend) Verify(proposal istanbul.Proposal) (time.Duration, error) { 464 // Check if the proposal is a valid block 465 block := &types.Block{} 466 block, ok := proposal.(*types.Block) 467 if !ok { 468 sb.logger.Error("Invalid proposal, %v", proposal) 469 return 0, errInvalidProposal 470 } 471 472 // check bad block 473 if sb.hasBadProposal(block.Hash()) { 474 return 0, core.ErrBlacklistedHash 475 } 476 477 // check block body 478 txnHash := types.DeriveSha(block.Transactions()) 479 uncleHash := types.CalcUncleHash(block.Uncles()) 480 if txnHash != block.Header().TxHash { 481 return 0, errMismatchTxhashes 482 } 483 if uncleHash != nilUncleHash { 484 return 0, errInvalidUncleHash 485 } 486 487 // The author should be the first person to propose the block to ensure that randomness matches up. 488 addr, err := sb.Author(block.Header()) 489 if err != nil { 490 sb.logger.Error("Could not recover orignal author of the block to verify the randomness", "err", err, "func", "Verify") 491 return 0, errInvalidProposal 492 } else if addr != block.Header().Coinbase { 493 sb.logger.Error("Original author of the block does not match the coinbase", "addr", addr, "coinbase", block.Header().Coinbase, "func", "Verify") 494 return 0, errInvalidCoinbase 495 } 496 497 err = sb.VerifyHeader(sb.chain, block.Header(), false) 498 499 // ignore errEmptyAggregatedSeal error because we don't have the committed seals yet 500 if err != nil && err != errEmptyAggregatedSeal { 501 if err == consensus.ErrFutureBlock { 502 return time.Unix(block.Header().Time.Int64(), 0).Sub(now()), consensus.ErrFutureBlock 503 } else { 504 return 0, err 505 } 506 } 507 508 // Process the block to verify that the transactions are valid and to retrieve the resulting state and receipts 509 // Get the state from this block's parent. 510 state, err := sb.stateAt(block.Header().ParentHash) 511 if err != nil { 512 sb.logger.Error("verify - Error in getting the block's parent's state", "parentHash", block.Header().ParentHash.Hex(), "err", err) 513 return 0, err 514 } 515 516 // Make a copy of the state 517 state = state.Copy() 518 519 // Apply this block's transactions to update the state 520 receipts, _, usedGas, err := sb.processBlock(block, state) 521 if err != nil { 522 sb.logger.Error("verify - Error in processing the block", "err", err) 523 return 0, err 524 } 525 526 // Validate the block 527 if err := sb.validateState(block, state, receipts, usedGas); err != nil { 528 sb.logger.Error("verify - Error in validating the block", "err", err) 529 return 0, err 530 } 531 532 // verify the validator set diff if this is the last block of the epoch 533 if istanbul.IsLastBlockOfEpoch(block.Header().Number.Uint64(), sb.config.Epoch) { 534 if err := sb.verifyValSetDiff(proposal, block, state); err != nil { 535 sb.logger.Error("verify - Error in verifying the val set diff", "err", err) 536 return 0, err 537 } 538 } 539 540 return 0, err 541 } 542 543 func (sb *Backend) getNewValidatorSet(header *types.Header, state *state.StateDB) ([]istanbul.ValidatorData, error) { 544 newValSetAddresses, err := election.GetElectedValidators(header, state) 545 if err != nil { 546 return nil, err 547 } 548 newValSet, err := validators.GetValidatorData(header, state, newValSetAddresses) 549 return newValSet, err 550 } 551 552 func (sb *Backend) verifyValSetDiff(proposal istanbul.Proposal, block *types.Block, state *state.StateDB) error { 553 header := block.Header() 554 555 // Ensure that the extra data format is satisfied 556 istExtra, err := types.ExtractIstanbulExtra(header) 557 if err != nil { 558 return err 559 } 560 561 newValSet, err := sb.getNewValidatorSet(block.Header(), state) 562 if err != nil { 563 if len(istExtra.AddedValidators) != 0 || istExtra.RemovedValidators.BitLen() != 0 { 564 sb.logger.Error("verifyValSetDiff - Invalid val set diff. Non empty diff when it should be empty.", "addedValidators", common.ConvertToStringSlice(istExtra.AddedValidators), "removedValidators", istExtra.RemovedValidators.Text(16)) 565 return errInvalidValidatorSetDiff 566 } 567 } else { 568 parentValidators := sb.ParentBlockValidators(proposal) 569 oldValSet := make([]istanbul.ValidatorData, 0, parentValidators.Size()) 570 571 for _, val := range parentValidators.List() { 572 oldValSet = append(oldValSet, istanbul.ValidatorData{ 573 val.Address(), 574 val.BLSPublicKey(), 575 }) 576 } 577 578 addedValidators, removedValidators := istanbul.ValidatorSetDiff(oldValSet, newValSet) 579 580 addedValidatorsAddresses := make([]common.Address, 0, len(addedValidators)) 581 addedValidatorsPublicKeys := make([]blscrypto.SerializedPublicKey, 0, len(addedValidators)) 582 for _, val := range addedValidators { 583 addedValidatorsAddresses = append(addedValidatorsAddresses, val.Address) 584 addedValidatorsPublicKeys = append(addedValidatorsPublicKeys, val.BLSPublicKey) 585 } 586 587 if !istanbul.CompareValidatorSlices(addedValidatorsAddresses, istExtra.AddedValidators) || removedValidators.Cmp(istExtra.RemovedValidators) != 0 || !istanbul.CompareValidatorPublicKeySlices(addedValidatorsPublicKeys, istExtra.AddedValidatorsPublicKeys) { 588 sb.logger.Error("verifyValSetDiff - Invalid val set diff. Comparison failed. ", "got addedValidators", common.ConvertToStringSlice(istExtra.AddedValidators), "got removedValidators", istExtra.RemovedValidators.Text(16), "got addedValidatorsPublicKeys", istanbul.ConvertPublicKeysToStringSlice(istExtra.AddedValidatorsPublicKeys), "expected addedValidators", common.ConvertToStringSlice(addedValidatorsAddresses), "expected removedValidators", removedValidators.Text(16), "expected addedValidatorsPublicKeys", istanbul.ConvertPublicKeysToStringSlice(addedValidatorsPublicKeys)) 589 return errInvalidValidatorSetDiff 590 } 591 } 592 593 return nil 594 } 595 596 // Sign implements istanbul.Backend.Sign 597 func (sb *Backend) Sign(data []byte) ([]byte, error) { 598 if sb.signFn == nil { 599 return nil, errInvalidSigningFn 600 } 601 hashData := crypto.Keccak256(data) 602 sb.signFnMu.RLock() 603 defer sb.signFnMu.RUnlock() 604 return sb.signFn(accounts.Account{Address: sb.address}, hashData) 605 } 606 607 func (sb *Backend) SignBlockHeader(data []byte) (blscrypto.SerializedSignature, error) { 608 if sb.signHashBLSFn == nil { 609 return blscrypto.SerializedSignature{}, errInvalidSigningFn 610 } 611 sb.signFnMu.RLock() 612 defer sb.signFnMu.RUnlock() 613 return sb.signHashBLSFn(accounts.Account{Address: sb.address}, data) 614 } 615 616 func (sb *Backend) SignBLSWithCompositeHash(data []byte) (blscrypto.SerializedSignature, error) { 617 if sb.signMessageBLSFn == nil { 618 return blscrypto.SerializedSignature{}, errInvalidSigningFn 619 } 620 sb.signFnMu.RLock() 621 defer sb.signFnMu.RUnlock() 622 // Currently, ExtraData is unused. In the future, it could include data that could be used to introduce 623 // "firmware-level" protection. Such data could include data that the SNARK doesn't necessarily need, 624 // such as the block number, which can be used by a hardware wallet to see that the block number 625 // is incrementing, without having to perform the two-level hashing, just one-level fast hashing. 626 return sb.signMessageBLSFn(accounts.Account{Address: sb.address}, data, []byte{}) 627 } 628 629 // CheckSignature implements istanbul.Backend.CheckSignature 630 func (sb *Backend) CheckSignature(data []byte, address common.Address, sig []byte) error { 631 signer, err := istanbul.GetSignatureAddress(data, sig) 632 if err != nil { 633 sb.logger.Error("Failed to get signer address", "err", err) 634 return err 635 } 636 // Compare derived addresses 637 if signer != address { 638 return errInvalidSignature 639 } 640 return nil 641 } 642 643 // HasBlock implements istanbul.Backend.HasBlock 644 func (sb *Backend) HasBlock(hash common.Hash, number *big.Int) bool { 645 return sb.chain.GetHeader(hash, number.Uint64()) != nil 646 } 647 648 // AuthorForBlock implements istanbul.Backend.AuthorForBlock 649 func (sb *Backend) AuthorForBlock(number uint64) common.Address { 650 if h := sb.chain.GetHeaderByNumber(number); h != nil { 651 a, _ := sb.Author(h) 652 return a 653 } 654 return common.ZeroAddress 655 } 656 657 func (sb *Backend) getValidators(number uint64, hash common.Hash) istanbul.ValidatorSet { 658 snap, err := sb.snapshot(sb.chain, number, hash, nil) 659 if err != nil { 660 sb.logger.Warn("Error getting snapshot", "number", number, "hash", hash, "err", err) 661 return validator.NewSet(nil) 662 } 663 return snap.ValSet 664 } 665 666 // validatorRandomnessAtBlockNumber calls into the EVM to get the randomness to use in proposer ordering at a given block. 667 func (sb *Backend) validatorRandomnessAtBlockNumber(number uint64, hash common.Hash) (common.Hash, error) { 668 lastBlockInPreviousEpoch := number 669 if number > 0 { 670 lastBlockInPreviousEpoch = number - istanbul.GetNumberWithinEpoch(number, sb.config.Epoch) 671 } 672 header := sb.chain.GetHeaderByNumber(lastBlockInPreviousEpoch) 673 if header == nil { 674 return common.Hash{}, errNoBlockHeader 675 } 676 state, err := sb.stateAt(header.Hash()) 677 if err != nil { 678 return common.Hash{}, err 679 } 680 return random.Random(header, state) 681 } 682 683 func (sb *Backend) getOrderedValidators(number uint64, hash common.Hash) istanbul.ValidatorSet { 684 valSet := sb.getValidators(number, hash) 685 if valSet.Size() == 0 { 686 return valSet 687 } 688 689 if sb.config.ProposerPolicy == istanbul.ShuffledRoundRobin { 690 seed, err := sb.validatorRandomnessAtBlockNumber(number, hash) 691 if err != nil { 692 if err == comm_errors.ErrRegistryContractNotDeployed { 693 sb.logger.Debug("Failed to set randomness for proposer selection", "block_number", number, "hash", hash, "error", err) 694 } else { 695 sb.logger.Warn("Failed to set randomness for proposer selection", "block_number", number, "hash", hash, "error", err) 696 } 697 } 698 valSet.SetRandomness(seed) 699 } 700 701 return valSet 702 } 703 704 // GetCurrentHeadBlock retrieves the last block 705 func (sb *Backend) GetCurrentHeadBlock() istanbul.Proposal { 706 return sb.currentBlock() 707 } 708 709 // GetCurrentHeadBlockAndAuthor retrieves the last block alongside the coinbase address for it 710 func (sb *Backend) GetCurrentHeadBlockAndAuthor() (istanbul.Proposal, common.Address) { 711 block := sb.currentBlock() 712 713 if block.Number().Cmp(common.Big0) == 0 { 714 return block, common.ZeroAddress 715 } 716 717 proposer, err := sb.Author(block.Header()) 718 719 if err != nil { 720 sb.logger.Error("Failed to get block proposer", "err", err) 721 return nil, common.ZeroAddress 722 } 723 724 // Return header only block here since we don't need block body 725 return block, proposer 726 } 727 728 func (sb *Backend) LastSubject() (istanbul.Subject, error) { 729 lastProposal, _ := sb.GetCurrentHeadBlockAndAuthor() 730 istExtra, err := types.ExtractIstanbulExtra(lastProposal.Header()) 731 if err != nil { 732 return istanbul.Subject{}, err 733 } 734 lastView := &istanbul.View{Sequence: lastProposal.Number(), Round: istExtra.AggregatedSeal.Round} 735 return istanbul.Subject{View: lastView, Digest: lastProposal.Hash()}, nil 736 } 737 738 func (sb *Backend) hasBadProposal(hash common.Hash) bool { 739 if sb.hasBadBlock == nil { 740 return false 741 } 742 return sb.hasBadBlock(hash) 743 } 744 745 func (sb *Backend) addProxy(node, externalNode *enode.Node) error { 746 if sb.proxyNode != nil { 747 return errProxyAlreadySet 748 } 749 750 sb.p2pserver.AddPeer(node, p2p.ProxyPurpose) 751 752 sb.proxyNode = &proxyInfo{node: node, externalNode: externalNode} 753 return nil 754 } 755 756 func (sb *Backend) removeProxy(node *enode.Node) { 757 if sb.proxyNode != nil && sb.proxyNode.node.ID() == node.ID() { 758 sb.p2pserver.RemovePeer(node, p2p.ProxyPurpose) 759 sb.proxyNode = nil 760 } 761 } 762 763 // RefreshValPeers will create 'validator' type peers to all the valset validators, and disconnect from the 764 // peers that are not part of the valset. 765 // It will also disconnect all validator connections if this node is not a validator. 766 // Note that adding and removing validators are idempotent operations. If the validator 767 // being added or removed is already added or removed, then a no-op will be done. 768 func (sb *Backend) RefreshValPeers(valset istanbul.ValidatorSet) { 769 sb.logger.Trace("Called RefreshValPeers", "valset length", valset.Size()) 770 771 if sb.broadcaster == nil { 772 return 773 } 774 775 sb.valEnodeTable.RefreshValPeers(valset, sb.ValidatorAddress()) 776 } 777 778 func (sb *Backend) ValidatorAddress() common.Address { 779 var localAddress common.Address 780 if sb.config.Proxy { 781 localAddress = sb.config.ProxiedValidatorAddress 782 } else { 783 localAddress = sb.Address() 784 } 785 return localAddress 786 } 787 788 func (sb *Backend) ConnectToVals() { 789 // If this is a proxy, then refresh the val peers. Note that this will be done within Backend.Start 790 // for non proxied validators 791 if sb.config.Proxy { 792 headBlock := sb.GetCurrentHeadBlock() 793 valset := sb.getValidators(headBlock.Number().Uint64(), headBlock.Hash()) 794 sb.RefreshValPeers(valset) 795 } 796 }