github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/consensus/podc/backend/backend.go (about) 1 2 // Copyright 2017 AMIS Technologies 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 package backend 19 20 import ( 21 "crypto/ecdsa" 22 "sync" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/consensus" 26 "github.com/ethereum/go-ethereum/consensus/podc" 27 podcCore "github.com/ethereum/go-ethereum/consensus/podc/core" 28 "github.com/ethereum/go-ethereum/consensus/podc/validator" 29 "github.com/ethereum/go-ethereum/core" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/ethdb" 33 "github.com/ethereum/go-ethereum/event" 34 "github.com/ethereum/go-ethereum/log" 35 lru "github.com/hashicorp/golang-lru" 36 ) 37 38 func New(config *podc.Config, eventMux *event.TypeMux, privateKey *ecdsa.PrivateKey, db ethdb.Database) consensus.PoDC { 39 // Allocate the snapshot caches and create the engine 40 recents, _ := lru.NewARC(inmemorySnapshots) 41 backend := &simpleBackend{ 42 config: config, 43 eventMux: eventMux, 44 //istanbulEventMux: new(event.TypeMux), 45 podcEventMux: new(event.TypeMux), 46 privateKey: privateKey, 47 address: crypto.PubkeyToAddress(privateKey.PublicKey), 48 logger: log.New("backend", "simple"), 49 db: db, 50 commitCh: make(chan *types.Block, 1), 51 recents: recents, 52 candidates: make(map[common.Address]bool), 53 } 54 return backend 55 } 56 57 // ---------------------------------------------------------------------------- 58 59 type simpleBackend struct { 60 config *podc.Config 61 eventMux *event.TypeMux 62 podcEventMux *event.TypeMux 63 privateKey *ecdsa.PrivateKey 64 address common.Address 65 66 core podcCore.Engine 67 logger log.Logger 68 quitSync chan struct{} 69 db ethdb.Database 70 timeout uint64 71 chain consensus.ChainReader 72 inserter func(block *types.Block) error 73 74 // the channels for istanbul engine notifications 75 commitCh chan *types.Block 76 proposedBlockHash common.Hash 77 sealMu sync.Mutex 78 79 // Current list of candidates we are pushing 80 candidates map[common.Address]bool 81 // Protects the signer fields 82 candidatesLock sync.RWMutex 83 // Snapshots for recent block to speed up reorgs 84 recents *lru.ARCCache 85 } 86 87 // Address implements istanbul.Backend.Address 88 func (sb *simpleBackend) Address() common.Address { 89 return sb.address 90 } 91 92 93 //Validators implements PoDC.Backend.Validators 94 func (sb *simpleBackend) Validators(proposal podc.Proposal) podc.ValidatorSet { 95 snap, err := sb.snapshot(sb.chain, proposal.Number().Uint64(), proposal.Hash(), nil) 96 if err != nil { 97 return validator.NewSet(nil, sb.config.ProposerPolicy) // 지금은 라운드로빈으로, 동작 예정, 98 } 99 return snap.ValSet 100 } 101 102 func (sb *simpleBackend) Send(payload []byte, target common.Address) error { 103 go sb.eventMux.Post(podc.ConsensusDataEvent{ 104 Target: target, 105 Data: payload, 106 }) 107 return nil 108 } 109 110 111 // 112 113 // Broadcast implements podc.Backend.Send 114 func (sb *simpleBackend) Broadcast(valSet podc.ValidatorSet, payload []byte) error { 115 116 // 모든 Validator 리스트에 다 보냄. 117 for _, val := range valSet.List() { 118 if val.Address() == sb.Address() { 119 // send to self 120 msg := podc.MessageEvent{ 121 Payload: payload, 122 } 123 go sb.podcEventMux.Post(msg) 124 125 } else { 126 // send to other peers 127 sb.Send(payload, val.Address()) 128 129 } 130 } 131 return nil 132 } 133 134 func (sb *simpleBackend) Multicast(payload []byte, targets []common.Address) error { 135 for _, addr := range targets { 136 if addr == sb.Address() { 137 msg := podc.MessageEvent{ 138 Payload: payload, 139 } 140 go sb.podcEventMux.Post(msg) 141 } else { 142 sb.Send(payload, addr) 143 } 144 } 145 return nil 146 } 147 148 // Commit implements podc.Backend.Commit 149 func (sb *simpleBackend) Commit(proposal podc.Proposal, seals []byte) error { 150 // Check if the proposal is a valid block 151 block := &types.Block{} 152 block, ok := proposal.(*types.Block) 153 if !ok { 154 sb.logger.Error("Invalid proposal, %v", proposal) 155 return errInvalidProposal 156 } 157 158 h := block.Header() 159 // Append seals into extra-data 160 err := writeCommittedSeals(h, seals) 161 if err != nil { 162 return err 163 } 164 // update block's header 165 block = block.WithSeal(h) 166 167 sb.logger.Info("Committed", "address", sb.Address(), "hash", proposal.Hash(), "number", proposal.Number().Uint64()) 168 // - if the proposed and committed blocks are the same, send the proposed hash 169 // to commit channel, which is being watched inside the engine.Seal() function. 170 // - otherwise, we try to insert the block. 171 // -- if success, the ChainHeadEvent event will be broadcasted, try to build 172 // the next block and the previous Seal() will be stopped. 173 // -- otherwise, a error will be returned and a round change event will be fired. 174 175 // TODO-REAP: temporarily disable 176 // if sb.proposedBlockHash == block.Hash() { 177 // // feed block hash to Seal() and wait the Seal() result 178 // sb.commitCh <- block 179 // // TODO: how do we check the block is inserted correctly? 180 // return nil 181 // } 182 183 return sb.inserter(block) 184 } 185 186 // NextRound will broadcast ChainHeadEvent to trigger next seal() 187 188 func (sb *simpleBackend) NextRound() error { 189 header := sb.chain.CurrentHeader() 190 sb.logger.Debug("NextRound", "address", sb.Address(), "current_hash", header.Hash(), "current_number", header.Number) 191 go sb.eventMux.Post(core.ChainHeadEvent{}) 192 return nil 193 } 194 195 // EventMux implements PoDC.Backend.EventMux 196 func (sb *simpleBackend) EventMux() *event.TypeMux { 197 return sb.podcEventMux 198 } 199 200 // Verify implements podc.Backend.Verify 201 func (sb *simpleBackend) Verify(proposal podc.Proposal) error { 202 // Check if the proposal is a valid block 203 block := &types.Block{} 204 block, ok := proposal.(*types.Block) 205 if !ok { 206 sb.logger.Error("Invalid proposal, %v", proposal) 207 return errInvalidProposal 208 } 209 // verify the header of proposed block 210 err := sb.VerifyHeader(sb.chain, block.Header(), false) 211 // Ignore errEmptyCommittedSeals error because we don't have the committed seals yet 212 if err != nil && err != errEmptyCommittedSeals { 213 return err 214 } 215 return nil 216 } 217 218 // Sign implements podc.Backend.Sign 219 func (sb *simpleBackend) Sign(data []byte) ([]byte, error) { 220 hashData := crypto.Keccak256([]byte(data)) 221 return crypto.Sign(hashData, sb.privateKey) 222 } 223 224 func (sb *simpleBackend) CheckSignature(data []byte, address common.Address, sig []byte) error { 225 signer, err := podc.GetSignatureAddress(data, sig) 226 if err != nil { 227 log.Error("Failed to get signer address", "err", err) 228 return err 229 } 230 // Compare derived addresses 231 if signer != address { 232 return errInvalidSignature 233 } 234 return nil 235 }