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