github.com/Night-mk/quorum@v21.1.0+incompatible/raft/minter.go (about) 1 // Copyright 2015 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 raft 18 19 import ( 20 "fmt" 21 "sync" 22 "sync/atomic" 23 "time" 24 25 "github.com/eapache/channels" 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/common/hexutil" 28 "github.com/ethereum/go-ethereum/consensus/ethash" 29 "github.com/ethereum/go-ethereum/core" 30 "github.com/ethereum/go-ethereum/core/state" 31 "github.com/ethereum/go-ethereum/core/types" 32 "github.com/ethereum/go-ethereum/core/vm" 33 "github.com/ethereum/go-ethereum/crypto" 34 "github.com/ethereum/go-ethereum/ethdb" 35 "github.com/ethereum/go-ethereum/event" 36 "github.com/ethereum/go-ethereum/log" 37 "github.com/ethereum/go-ethereum/params" 38 "github.com/ethereum/go-ethereum/rlp" 39 ) 40 41 var ( 42 extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for arbitrary signer vanity 43 ) 44 45 // Current state information for building the next block 46 type work struct { 47 config *params.ChainConfig 48 publicState *state.StateDB 49 privateState *state.StateDB 50 Block *types.Block 51 header *types.Header 52 } 53 54 type minter struct { 55 config *params.ChainConfig 56 mu sync.Mutex 57 mux *event.TypeMux 58 eth *RaftService 59 chain *core.BlockChain 60 chainDb ethdb.Database 61 coinbase common.Address 62 minting int32 // Atomic status counter 63 shouldMine *channels.RingChannel 64 blockTime time.Duration 65 speculativeChain *speculativeChain 66 67 invalidRaftOrderingChan chan InvalidRaftOrdering 68 chainHeadChan chan core.ChainHeadEvent 69 chainHeadSub event.Subscription 70 txPreChan chan core.NewTxsEvent 71 txPreSub event.Subscription 72 } 73 74 type extraSeal struct { 75 RaftId []byte // RaftID of the block minter 76 Signature []byte // Signature of the block minter 77 } 78 79 func newMinter(config *params.ChainConfig, eth *RaftService, blockTime time.Duration) *minter { 80 minter := &minter{ 81 config: config, 82 eth: eth, 83 mux: eth.EventMux(), 84 chainDb: eth.ChainDb(), 85 chain: eth.BlockChain(), 86 shouldMine: channels.NewRingChannel(1), 87 blockTime: blockTime, 88 speculativeChain: newSpeculativeChain(), 89 90 invalidRaftOrderingChan: make(chan InvalidRaftOrdering, 1), 91 chainHeadChan: make(chan core.ChainHeadEvent, core.GetChainHeadChannleSize()), 92 txPreChan: make(chan core.NewTxsEvent, 4096), 93 } 94 95 minter.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(minter.chainHeadChan) 96 minter.txPreSub = eth.TxPool().SubscribeNewTxsEvent(minter.txPreChan) 97 98 minter.speculativeChain.clear(minter.chain.CurrentBlock()) 99 100 go minter.eventLoop() 101 go minter.mintingLoop() 102 103 return minter 104 } 105 106 func (minter *minter) start() { 107 atomic.StoreInt32(&minter.minting, 1) 108 minter.requestMinting() 109 } 110 111 func (minter *minter) stop() { 112 minter.mu.Lock() 113 defer minter.mu.Unlock() 114 115 minter.speculativeChain.clear(minter.chain.CurrentBlock()) 116 atomic.StoreInt32(&minter.minting, 0) 117 } 118 119 // Notify the minting loop that minting should occur, if it's not already been 120 // requested. Due to the use of a RingChannel, this function is idempotent if 121 // called multiple times before the minting occurs. 122 func (minter *minter) requestMinting() { 123 minter.shouldMine.In() <- struct{}{} 124 } 125 126 type AddressTxes map[common.Address]types.Transactions 127 128 func (minter *minter) updateSpeculativeChainPerNewHead(newHeadBlock *types.Block) { 129 minter.mu.Lock() 130 defer minter.mu.Unlock() 131 132 minter.speculativeChain.accept(newHeadBlock) 133 } 134 135 func (minter *minter) updateSpeculativeChainPerInvalidOrdering(headBlock *types.Block, invalidBlock *types.Block) { 136 invalidHash := invalidBlock.Hash() 137 138 log.Info("Handling InvalidRaftOrdering", "invalid block", invalidHash, "current head", headBlock.Hash()) 139 140 minter.mu.Lock() 141 defer minter.mu.Unlock() 142 143 // 1. if the block is not in our db, exit. someone else mined this. 144 if !minter.chain.HasBlock(invalidHash, invalidBlock.NumberU64()) { 145 log.Info("Someone else mined invalid block; ignoring", "block", invalidHash) 146 147 return 148 } 149 150 minter.speculativeChain.unwindFrom(invalidHash, headBlock) 151 } 152 153 func (minter *minter) eventLoop() { 154 defer minter.chainHeadSub.Unsubscribe() 155 defer minter.txPreSub.Unsubscribe() 156 157 for { 158 select { 159 case ev := <-minter.chainHeadChan: 160 newHeadBlock := ev.Block 161 162 if atomic.LoadInt32(&minter.minting) == 1 { 163 minter.updateSpeculativeChainPerNewHead(newHeadBlock) 164 165 // 166 // TODO(bts): not sure if this is the place, but we're going to 167 // want to put an upper limit on our speculative mining chain 168 // length. 169 // 170 171 minter.requestMinting() 172 } else { 173 minter.mu.Lock() 174 minter.speculativeChain.setHead(newHeadBlock) 175 minter.mu.Unlock() 176 } 177 178 case <-minter.txPreChan: 179 if atomic.LoadInt32(&minter.minting) == 1 { 180 minter.requestMinting() 181 } 182 183 case ev := <-minter.invalidRaftOrderingChan: 184 headBlock := ev.headBlock 185 invalidBlock := ev.invalidBlock 186 187 minter.updateSpeculativeChainPerInvalidOrdering(headBlock, invalidBlock) 188 189 // system stopped 190 case <-minter.chainHeadSub.Err(): 191 return 192 case <-minter.txPreSub.Err(): 193 return 194 } 195 } 196 } 197 198 // Returns a wrapper around no-arg func `f` which can be called without limit 199 // and returns immediately: this will call the underlying func `f` at most once 200 // every `rate`. If this function is called more than once before the underlying 201 // `f` is invoked (per this rate limiting), `f` will only be called *once*. 202 // 203 // TODO(joel): this has a small bug in that you can't call it *immediately* when 204 // first allocated. 205 func throttle(rate time.Duration, f func()) func() { 206 request := channels.NewRingChannel(1) 207 208 // every tick, block waiting for another request. then serve it immediately 209 go func() { 210 ticker := time.NewTicker(rate) 211 defer ticker.Stop() 212 213 for range ticker.C { 214 <-request.Out() 215 f() 216 } 217 }() 218 219 return func() { 220 request.In() <- struct{}{} 221 } 222 } 223 224 // This function spins continuously, blocking until a block should be created 225 // (via requestMinting()). This is throttled by `minter.blockTime`: 226 // 227 // 1. A block is guaranteed to be minted within `blockTime` of being 228 // requested. 229 // 2. We never mint a block more frequently than `blockTime`. 230 func (minter *minter) mintingLoop() { 231 throttledMintNewBlock := throttle(minter.blockTime, func() { 232 if atomic.LoadInt32(&minter.minting) == 1 { 233 minter.mintNewBlock() 234 } 235 }) 236 237 for range minter.shouldMine.Out() { 238 throttledMintNewBlock() 239 } 240 } 241 242 func generateNanoTimestamp(parent *types.Block) (tstamp int64) { 243 parentTime := int64(parent.Time()) 244 tstamp = time.Now().UnixNano() 245 246 if parentTime >= tstamp { 247 // Each successive block needs to be after its predecessor. 248 tstamp = parentTime + 1 249 } 250 251 return 252 } 253 254 // Assumes mu is held. 255 func (minter *minter) createWork() *work { 256 parent := minter.speculativeChain.head 257 parentNumber := parent.Number() 258 tstamp := generateNanoTimestamp(parent) 259 260 header := &types.Header{ 261 ParentHash: parent.Hash(), 262 Number: parentNumber.Add(parentNumber, common.Big1), 263 Difficulty: ethash.CalcDifficulty(minter.config, uint64(tstamp), parent.Header()), 264 GasLimit: minter.eth.calcGasLimitFunc(parent), 265 GasUsed: 0, 266 Coinbase: minter.coinbase, 267 Time: uint64(tstamp), 268 } 269 270 publicState, privateState, err := minter.chain.StateAt(parent.Root()) 271 if err != nil { 272 panic(fmt.Sprint("failed to get parent state: ", err)) 273 } 274 275 return &work{ 276 config: minter.config, 277 publicState: publicState, 278 privateState: privateState, 279 header: header, 280 } 281 } 282 283 func (minter *minter) getTransactions() *types.TransactionsByPriceAndNonce { 284 allAddrTxes, err := minter.eth.TxPool().Pending() 285 if err != nil { // TODO: handle 286 panic(err) 287 } 288 addrTxes := minter.speculativeChain.withoutProposedTxes(allAddrTxes) 289 signer := types.MakeSigner(minter.chain.Config(), minter.chain.CurrentBlock().Number()) 290 return types.NewTransactionsByPriceAndNonce(signer, addrTxes) 291 } 292 293 // Sends-off events asynchronously. 294 func (minter *minter) firePendingBlockEvents(logs []*types.Log) { 295 // Copy logs before we mutate them, adding a block hash. 296 copiedLogs := make([]*types.Log, len(logs)) 297 for i, l := range logs { 298 copiedLogs[i] = new(types.Log) 299 *copiedLogs[i] = *l 300 } 301 302 go func() { 303 minter.mux.Post(core.PendingLogsEvent{Logs: copiedLogs}) 304 minter.mux.Post(core.PendingStateEvent{}) 305 }() 306 } 307 308 func (minter *minter) mintNewBlock() { 309 minter.mu.Lock() 310 defer minter.mu.Unlock() 311 312 work := minter.createWork() 313 transactions := minter.getTransactions() 314 315 committedTxes, publicReceipts, _, logs := work.commitTransactions(transactions, minter.chain) 316 txCount := len(committedTxes) 317 318 if txCount == 0 { 319 log.Info("Not minting a new block since there are no pending transactions") 320 return 321 } 322 323 minter.firePendingBlockEvents(logs) 324 325 header := work.header 326 327 // commit state root after all state transitions. 328 ethash.AccumulateRewards(minter.chain.Config(), work.publicState, header, nil) 329 header.Root = work.publicState.IntermediateRoot(minter.chain.Config().IsEIP158(work.header.Number)) 330 331 // update block hash since it is now available, but was not when the 332 // receipt/log of individual transactions were created: 333 headerHash := header.Hash() 334 for _, l := range logs { 335 l.BlockHash = headerHash 336 } 337 338 //Sign the block and build the extraSeal struct 339 extraSealBytes := minter.buildExtraSeal(headerHash) 340 341 // add vanity and seal to header 342 // NOTE: leaving vanity blank for now as a space for any future data 343 header.Extra = make([]byte, extraVanity+len(extraSealBytes)) 344 copy(header.Extra[extraVanity:], extraSealBytes) 345 346 block := types.NewBlock(header, committedTxes, nil, publicReceipts) 347 348 log.Info("Generated next block", "block num", block.Number(), "num txes", txCount) 349 350 deleteEmptyObjects := minter.chain.Config().IsEIP158(block.Number()) 351 if err := minter.chain.CommitBlockWithState(deleteEmptyObjects, work.publicState, work.privateState); err != nil { 352 panic(err) 353 } 354 355 minter.speculativeChain.extend(block) 356 357 minter.mux.Post(core.NewMinedBlockEvent{Block: block}) 358 359 elapsed := time.Since(time.Unix(0, int64(header.Time))) 360 log.Info("🔨 Mined block", "number", block.Number(), "hash", fmt.Sprintf("%x", block.Hash().Bytes()[:4]), "elapsed", elapsed) 361 } 362 363 func (env *work) commitTransactions(txes *types.TransactionsByPriceAndNonce, bc *core.BlockChain) (types.Transactions, types.Receipts, types.Receipts, []*types.Log) { 364 var allLogs []*types.Log 365 var committedTxes types.Transactions 366 var publicReceipts types.Receipts 367 var privateReceipts types.Receipts 368 369 gp := new(core.GasPool).AddGas(env.header.GasLimit) 370 txCount := 0 371 372 for { 373 tx := txes.Peek() 374 if tx == nil { 375 break 376 } 377 378 env.publicState.Prepare(tx.Hash(), common.Hash{}, txCount) 379 380 publicReceipt, privateReceipt, err := env.commitTransaction(tx, bc, gp) 381 switch { 382 case err != nil: 383 log.Info("TX failed, will be removed", "hash", tx.Hash(), "err", err) 384 txes.Pop() // skip rest of txes from this account 385 default: 386 txCount++ 387 committedTxes = append(committedTxes, tx) 388 389 publicReceipts = append(publicReceipts, publicReceipt) 390 allLogs = append(allLogs, publicReceipt.Logs...) 391 392 if privateReceipt != nil { 393 privateReceipts = append(privateReceipts, privateReceipt) 394 allLogs = append(allLogs, privateReceipt.Logs...) 395 } 396 397 txes.Shift() 398 } 399 } 400 401 return committedTxes, publicReceipts, privateReceipts, allLogs 402 } 403 404 func (env *work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (*types.Receipt, *types.Receipt, error) { 405 publicSnapshot := env.publicState.Snapshot() 406 privateSnapshot := env.privateState.Snapshot() 407 408 var author *common.Address 409 var vmConf vm.Config 410 txnStart := time.Now() 411 publicReceipt, privateReceipt, err := core.ApplyTransaction(env.config, bc, author, gp, env.publicState, env.privateState, env.header, tx, &env.header.GasUsed, vmConf) 412 if err != nil { 413 env.publicState.RevertToSnapshot(publicSnapshot) 414 env.privateState.RevertToSnapshot(privateSnapshot) 415 416 return nil, nil, err 417 } 418 log.EmitCheckpoint(log.TxCompleted, "tx", tx.Hash().Hex(), "time", time.Since(txnStart)) 419 420 return publicReceipt, privateReceipt, nil 421 } 422 423 func (minter *minter) buildExtraSeal(headerHash common.Hash) []byte { 424 //Sign the headerHash 425 nodeKey := minter.eth.nodeKey 426 sig, err := crypto.Sign(headerHash.Bytes(), nodeKey) 427 if err != nil { 428 log.Warn("Block sealing failed", "err", err) 429 } 430 431 //build the extraSeal struct 432 raftIdString := hexutil.EncodeUint64(uint64(minter.eth.raftProtocolManager.raftId)) 433 434 extra := extraSeal{ 435 RaftId: []byte(raftIdString[2:]), //remove the 0x prefix 436 Signature: sig, 437 } 438 439 //encode to byte array for storage 440 extraDataBytes, err := rlp.EncodeToBytes(extra) 441 if err != nil { 442 log.Warn("Header.Extra Data Encoding failed", "err", err) 443 } 444 445 return extraDataBytes 446 }