github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/backend/backend.go (about) 1 // Copyright 2020 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package backend 18 19 import ( 20 "crypto/ecdsa" 21 "math/big" 22 "sync" 23 "time" 24 25 "github.com/bigzoro/my_simplechain/common" 26 "github.com/bigzoro/my_simplechain/consensus" 27 "github.com/bigzoro/my_simplechain/consensus/pbft" 28 pc "github.com/bigzoro/my_simplechain/consensus/pbft/core" 29 "github.com/bigzoro/my_simplechain/consensus/pbft/validator" 30 "github.com/bigzoro/my_simplechain/core" 31 "github.com/bigzoro/my_simplechain/core/types" 32 "github.com/bigzoro/my_simplechain/crypto" 33 "github.com/bigzoro/my_simplechain/ethdb" 34 "github.com/bigzoro/my_simplechain/event" 35 "github.com/bigzoro/my_simplechain/log" 36 lru "github.com/hashicorp/golang-lru" 37 ) 38 39 const ( 40 // fetcherID is the ID indicates the block is from Istanbul engine 41 fetcherID = "istanbul" 42 ) 43 44 // New creates an Ethereum backend for Istanbul core engine. 45 func New(config *pbft.Config, privateKey *ecdsa.PrivateKey, db ethdb.Database) consensus.Pbft { 46 // Allocate the snapshot caches and create the engine 47 recents, _ := lru.NewARC(inmemorySnapshots) 48 recentMessages, _ := lru.NewARC(inmemoryPeers) 49 knownMessages, _ := lru.NewARC(inmemoryMessages) 50 proposal2conclusion, _ := lru.NewARC(inmemoryP2C) 51 backend := &backend{ 52 config: config, 53 pbftEventMux: new(event.TypeMux), 54 privateKey: privateKey, 55 address: crypto.PubkeyToAddress(privateKey.PublicKey), 56 logger: log.New(), 57 db: db, 58 commitCh: make(chan *types.Block, 1), 59 recents: recents, 60 proposal2conclusion: proposal2conclusion, 61 candidates: make(map[common.Address]bool), 62 coreStarted: false, 63 recentMessages: recentMessages, 64 knownMessages: knownMessages, 65 } 66 backend.core = pc.New(backend, backend.config) 67 return backend 68 } 69 70 // ---------------------------------------------------------------------------- 71 72 type backend struct { 73 config *pbft.Config 74 pbftEventMux *event.TypeMux 75 privateKey *ecdsa.PrivateKey 76 address common.Address 77 core pc.Engine 78 logger log.Logger 79 db ethdb.Database 80 chain consensus.ChainReader 81 chainWriter consensus.ChainWriter 82 currentBlock func() *types.Block 83 hasBadBlock func(hash common.Hash) bool 84 85 // the channels for pbft engine notifications 86 commitCh chan *types.Block 87 proposedBlockHash common.Hash 88 sealMu sync.Mutex 89 coreStarted bool 90 coreMu sync.RWMutex 91 92 // Current list of candidates we are pushing 93 candidates map[common.Address]bool 94 // Protects the signer fields 95 candidatesLock sync.RWMutex 96 // Snapshots for recent block to speed up reorgs 97 recents *lru.ARCCache 98 // proposal2conclusion store proposedHash to conclusionHash 99 proposal2conclusion *lru.ARCCache 100 101 // event subscription for ChainHeadEvent event 102 broadcaster consensus.Broadcaster 103 sealer consensus.Sealer 104 txPool consensus.TxPool 105 106 recentMessages *lru.ARCCache // the cache of peer's messages 107 knownMessages *lru.ARCCache // the cache of self messages 108 109 sealStart time.Time // record engine starting seal time 110 execCost time.Duration 111 } 112 113 func (sb *backend) GetCurrentBlock() *types.Block { 114 return sb.core.GetCurrentBlock() 115 } 116 117 // zekun: HACK 118 func (sb *backend) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 119 return new(big.Int) 120 } 121 122 // Address implements pbft.Backend.Address 123 func (sb *backend) Address() common.Address { 124 return sb.address 125 } 126 127 // Validators implements pbft.Backend.Validators 128 func (sb *backend) Validators(proposal pbft.Conclusion) pbft.ValidatorSet { 129 return sb.getValidators(proposal.Number().Uint64(), proposal.Hash()) 130 } 131 132 // Broadcast send to others. implements pbft.Backend.Broadcast 133 func (sb *backend) Broadcast(valSet pbft.ValidatorSet, sender common.Address, payload []byte) error { 134 //sb.Gossip(valSet, payload) 135 sb.Guidance(valSet, sender, payload) 136 return nil 137 } 138 139 // BroadcastMsg sends a message to specific validators. implements pbft.Backend.BroadcastMsg 140 func (sb *backend) BroadcastMsg(ps map[common.Address]consensus.Peer, hash common.Hash, payload []byte) error { 141 sb.knownMessages.Add(hash, true) 142 143 for addr, p := range ps { 144 ms, ok := sb.recentMessages.Get(addr) 145 var m *lru.ARCCache 146 if ok { 147 m, _ = ms.(*lru.ARCCache) 148 if _, k := m.Get(hash); k { 149 // This peer had this event, skip it 150 continue 151 } 152 } else { 153 m, _ = lru.NewARC(inmemoryMessages) 154 } 155 156 m.Add(hash, true) 157 sb.recentMessages.Add(addr, m) 158 159 go func(peer consensus.Peer) { 160 if err := peer.Send(PbftMsg, payload); err != nil { 161 log.Error("send PbftMsg failed", "error", err.Error()) 162 } 163 }(p) 164 } 165 166 return nil 167 } 168 169 // Post send to self 170 func (sb *backend) Post(payload []byte) { 171 msg := pbft.MessageEvent{ 172 Payload: payload, 173 } 174 go sb.pbftEventMux.Post(msg) 175 } 176 177 func (sb *backend) SendMsg(val pbft.Validators, payload []byte) error { 178 targets := make(map[common.Address]bool, val.Len()) 179 for _, v := range val { 180 targets[v.Address()] = true 181 } 182 ps := sb.broadcaster.FindPeers(targets) 183 184 for _, p := range ps { 185 go func(peer consensus.Peer) { 186 if err := peer.Send(PbftMsg, payload); err != nil { 187 log.Error("send PbftMsg failed", "error", err.Error()) 188 } 189 }(p) 190 } 191 return nil 192 } 193 194 func (sb *backend) Guidance(valSet pbft.ValidatorSet, sender common.Address, payload []byte) { 195 targets := make([]common.Address, 0, valSet.Size()) 196 myIndex, routeIndex := -1, -1 // -1 means not a route node index 197 for i, val := range valSet.List() { 198 if val.Address() == sb.Address() { 199 myIndex = i 200 } 201 if val.Address() == sender { 202 routeIndex = i 203 } 204 targets = append(targets, val.Address()) 205 } 206 207 if sb.broadcaster != nil { 208 hash := pbft.RLPHash(payload) 209 ps := sb.broadcaster.FindRoute(targets, myIndex, routeIndex) 210 sb.BroadcastMsg(ps, hash, payload) 211 } 212 } 213 214 func (sb *backend) MarkTransactionKnownBy(val pbft.Validator, txs types.Transactions) { 215 ps := sb.broadcaster.FindPeers(map[common.Address]bool{val.Address(): true}) 216 for _, p := range ps { 217 for _, tx := range txs { 218 p.MarkTransaction(tx.Hash()) 219 } 220 } 221 } 222 223 // Broadcast implements pbft.Backend.Gossip 224 func (sb *backend) Gossip(valSet pbft.ValidatorSet, payload []byte) { 225 targets := make(map[common.Address]bool) 226 for _, val := range valSet.List() { 227 if val.Address() != sb.Address() { 228 targets[val.Address()] = true 229 } 230 } 231 232 if sb.broadcaster != nil && len(targets) > 0 { 233 hash := pbft.RLPHash(payload) 234 ps := sb.broadcaster.FindPeers(targets) 235 sb.BroadcastMsg(ps, hash, payload) 236 } 237 } 238 239 // Commit implements pbft.Backend.Commit 240 func (sb *backend) Commit(conclusion pbft.Conclusion, commitSeals [][]byte) error { 241 // Check if the conclusion is a valid block 242 block, ok := conclusion.(*types.Block) 243 if !ok { 244 sb.logger.Error("Invalid conclusion, %v", conclusion) 245 return errInvalidProposal 246 } 247 248 h := block.Header() 249 // Append commitSeals into extra-data 250 err := writeCommittedSeals(h, commitSeals) 251 if err != nil { 252 return err 253 } 254 // update block's header 255 block = block.WithSeal(h) 256 257 hTime := time.Unix(int64(h.Time), 0) 258 delay := hTime.Sub(now()) 259 if sb.sealer != nil { 260 sb.sealer.OnCommit(block.NumberU64(), block.Transactions().Len()) 261 } 262 263 //log.Report("pbft consensus seal cost", 264 // "num", h.Number, "totalCost", time.Since(sb.sealStart), "execCost", sb.execCost) 265 266 // wait until block timestamp 267 if delay > time.Minute { 268 return errTooFarInFuture 269 } 270 <-time.After(delay) 271 272 // - if the proposed and committed blocks are the same, send the proposed hash 273 // to commit channel, which is being watched inside the engine.Seal() function. 274 // - otherwise, we try to insert the block. 275 // -- if success, the ChainHeadEvent event will be broadcasted, try to build 276 // the next block and the previous Seal() will be stopped. 277 // -- otherwise, a error will be returned and a round change event will be fired. 278 //if sb.proposedBlockHash == block.Hash() { 279 if sb.proposedBlockHash == block.PendingHash() { 280 // feed block hash to Seal() and wait the Seal() result 281 sb.commitCh <- block 282 283 } else { 284 // write block to block chain 285 if sb.chainWriter != nil { 286 err := sb.chainWriter.WriteBlock(block) 287 if err != nil { 288 return err 289 } 290 } 291 // broadcast new block 292 if sb.broadcaster != nil { 293 //sb.broadcaster.Enqueue(fetcherID, block) 294 // broadcast the block announce 295 sb.broadcaster.BroadcastBlock(block, false) 296 } 297 } 298 299 sb.logger.Warn("Committed new pbft block", "number", conclusion.Number().Uint64(), 300 "proposeHash", conclusion.PendingHash(), "hash", conclusion.Hash(), "txs", block.Transactions().Len(), 301 "elapsed", time.Since(hTime)) 302 303 return nil 304 } 305 306 func (sb *backend) GetForwardNodes(valList pbft.Validators) (map[common.Address]consensus.Peer, []common.Address) { 307 var ( 308 peers map[common.Address]consensus.Peer 309 forwardNodes []common.Address 310 ) 311 targets := make(map[common.Address]bool) 312 for _, val := range valList { 313 if val.Address() != sb.Address() { 314 targets[val.Address()] = true 315 } 316 } 317 if sb.broadcaster != nil && len(targets) > 0 { 318 peers = sb.broadcaster.FindPeers(targets) 319 for addr, ok := range targets { 320 if ok && peers[addr] == nil { 321 forwardNodes = append(forwardNodes, addr) 322 } 323 } 324 } 325 return peers, forwardNodes 326 } 327 328 // EventMux implements pbft.Backend.EventMux 329 func (sb *backend) EventMux() *event.TypeMux { 330 return sb.pbftEventMux 331 } 332 333 // Verify implements pbft.Backend.Verify 334 // Check if the proposal is a valid block 335 func (sb *backend) Verify(proposal pbft.Proposal, checkHeader, checkBody bool) (time.Duration, error) { 336 // Unpack proposal to raw block 337 var block *types.Block 338 switch pb := proposal.(type) { 339 case *types.Block: 340 block = pb 341 case *types.LightBlock: 342 block = &pb.Block 343 default: 344 sb.logger.Error("Invalid proposal(wrong type)", "proposal", proposal) 345 return 0, errInvalidProposal 346 } 347 348 // check bad block 349 if sb.HasBadProposal(block.PendingHash()) { // proposal only has pendingHash (fixed in blockchain) 350 //if sb.HasBadProposal(block.Hash()) { 351 return 0, core.ErrBlacklistedHash 352 } 353 354 // check block body 355 if checkBody { 356 err := sb.VerifyBody(block) 357 if err != nil { 358 return 0, err 359 } 360 } 361 362 // verify the header of proposed block 363 if !checkHeader { 364 return 0, nil 365 } 366 err := sb.VerifyHeader(sb.chain, block.Header(), false) 367 switch err { 368 // ignore errEmptyCommittedSeals error because we don't have the committed seals yet 369 case nil, errEmptyCommittedSeals: 370 return 0, nil 371 372 case consensus.ErrFutureBlock: 373 return time.Unix(int64(block.Header().Time), 0).Sub(now()), consensus.ErrFutureBlock 374 375 default: 376 return 0, err 377 } 378 } 379 380 func (sb *backend) VerifyBody(block *types.Block) error { 381 txnHash := types.DeriveSha(block.Transactions()) 382 uncleHash := types.CalcUncleHash(block.Uncles()) 383 if txnHash != block.Header().TxHash { 384 return errMismatchTxhashes 385 } 386 if uncleHash != nilUncleHash { 387 return errInvalidUncleHash 388 } 389 return nil 390 } 391 392 func (sb *backend) FillLightProposal(proposal pbft.LightProposal) (filled bool, missed []types.MissedTx, err error) { 393 block, ok := proposal.(*types.LightBlock) 394 if !ok { 395 sb.logger.Error("Invalid proposal(wrong type), %v", proposal) 396 return false, nil, errInvalidProposal 397 } 398 399 if sb.txPool == nil { 400 return false, nil, errNonExistentTxPool 401 } 402 403 // resize block transactions to digests size 404 *block.Transactions() = make(types.Transactions, len(block.TxDigests())) 405 // fill block transactions by txpool 406 filled = sb.txPool.InitLightBlock(block) 407 408 return filled, block.MissedTxs, nil 409 } 410 411 func (sb *backend) Execute(proposal pbft.Proposal) (pbft.Conclusion, error) { 412 var block *types.Block 413 switch pb := proposal.(type) { 414 case *types.Block: 415 block = pb 416 case *types.LightBlock: 417 block = &pb.Block 418 default: 419 sb.logger.Error("Invalid proposal(wrong type)", "proposal", proposal) 420 return nil, errInvalidProposal 421 } 422 423 if sb.sealer == nil { 424 return block, errNonExistentSealer 425 } 426 427 defer func(start time.Time) { 428 sb.logger.Debug("Execute Proposal", "pendingHash", proposal.PendingHash(), "usedTime", time.Since(start)) 429 sb.execCost = time.Since(start) 430 }(time.Now()) 431 432 if err := sb.txPool.CheckAndSetSender(types.Blocks{block}); err != nil { 433 return nil, err 434 } 435 return sb.chainWriter.Execute(block) 436 437 //return sb.sealer.Execute(block) //TODO:delete 438 } 439 440 func (sb *backend) OnTimeout() { 441 if sb.sealer != nil { 442 sb.sealer.OnTimeout() 443 } 444 } 445 446 // Sign implements pbft.Backend.Sign 447 func (sb *backend) Sign(data []byte) ([]byte, error) { 448 hashData := crypto.Keccak256(data) 449 return crypto.Sign(hashData, sb.privateKey) 450 } 451 452 // CheckSignature implements pbft.Backend.CheckSignature 453 func (sb *backend) CheckSignature(data []byte, address common.Address, sig []byte) error { 454 signer, err := pbft.GetSignatureAddress(data, sig) 455 if err != nil { 456 log.Error("Failed to get signer address", "err", err) 457 return err 458 } 459 // Compare derived addresses 460 if signer != address { 461 return errInvalidSignature 462 } 463 return nil 464 } 465 466 // HasProposal implements pbft.Backend.HashBlock 467 func (sb *backend) HasProposal(hash common.Hash, number *big.Int) (common.Hash, bool) { 468 cHash, ok := sb.proposal2conclusion.Get(hash) 469 if ok { 470 conclusionHash := cHash.(common.Hash) 471 return conclusionHash, sb.chain.GetHeader(conclusionHash, number.Uint64()) != nil 472 } 473 return common.Hash{}, false 474 } 475 476 func (sb *backend) AnnounceCommittedProposal(hash common.Hash, number *big.Int, to pbft.Validator) { 477 block := sb.chain.GetBlock(hash, number.Uint64()) 478 if block != nil { 479 for _, peer := range sb.broadcaster.FindPeers(map[common.Address]bool{to.Address(): true}) { 480 peer.AsyncSendNewBlockHash(block) 481 } 482 } 483 } 484 485 // GetProposer implements pbft.Backend.GetProposer 486 func (sb *backend) GetProposer(number uint64) common.Address { 487 if h := sb.chain.GetHeaderByNumber(number); h != nil { 488 a, _ := sb.Author(h) 489 return a 490 } 491 return common.Address{} 492 } 493 494 // ParentValidators implements pbft.Backend.ParentValidators 495 func (sb *backend) ParentValidators(proposal pbft.Proposal) pbft.ValidatorSet { 496 if block, ok := proposal.(*types.Block); ok { 497 return sb.getValidators(block.Number().Uint64()-1, block.ParentHash()) 498 } 499 return validator.NewSet(nil, sb.config.ProposerPolicy) 500 } 501 502 func (sb *backend) getValidators(number uint64, hash common.Hash) pbft.ValidatorSet { 503 snap, err := sb.snapshot(sb.chain, number, hash, nil) 504 if err != nil { 505 sb.logger.Warn("validators are not found in snapshot", "err", err) 506 return validator.NewSet(nil, sb.config.ProposerPolicy) 507 } 508 return snap.ValSet 509 } 510 511 func (sb *backend) LastProposal() (pbft.Proposal, pbft.Conclusion, common.Address) { 512 block := sb.currentBlock() // current block on blockchain 513 514 var proposer common.Address 515 if block.Number().Cmp(common.Big0) > 0 { 516 var err error 517 proposer, err = sb.Author(block.Header()) 518 if err != nil { 519 sb.logger.Error("Failed to get block proposer", "err", err) 520 return nil, nil, common.Address{} 521 } 522 } 523 524 // Return header only block here since we don't need block body 525 return block, block, proposer 526 } 527 528 func (sb *backend) HasBadProposal(hash common.Hash) bool { 529 if sb.hasBadBlock == nil { 530 return false 531 } 532 return sb.hasBadBlock(hash) 533 } 534 535 func (sb *backend) IsBlockHashLocked(hash common.Hash) bool { 536 return sb.core.IsHashLocked(hash) 537 } 538 539 func (sb *backend) Close() error { 540 return nil 541 }