github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/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/kisexp/xdchain/common" 27 "github.com/kisexp/xdchain/common/hexutil" 28 "github.com/kisexp/xdchain/consensus/ethash" 29 "github.com/kisexp/xdchain/core" 30 "github.com/kisexp/xdchain/core/state" 31 "github.com/kisexp/xdchain/core/types" 32 "github.com/kisexp/xdchain/core/vm" 33 "github.com/kisexp/xdchain/crypto" 34 "github.com/kisexp/xdchain/ethdb" 35 "github.com/kisexp/xdchain/event" 36 "github.com/kisexp/xdchain/log" 37 "github.com/kisexp/xdchain/params" 38 "github.com/kisexp/xdchain/rlp" 39 "github.com/kisexp/xdchain/trie" 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 := int64(parent.Time()) 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: uint64(tstamp), 269 } 270 271 publicState, privateStateManager, err := minter.chain.StateAt(parent.Root()) 272 if err != nil { 273 panic(fmt.Sprint("failed to get parent state: ", err)) 274 } 275 defaultPrivateState, err := privateStateManager.DefaultState() 276 if err != nil { 277 panic(fmt.Sprint("failed to get default private state: ", err)) 278 } 279 280 return &work{ 281 config: minter.config, 282 publicState: publicState, 283 privateState: defaultPrivateState, 284 header: header, 285 } 286 } 287 288 func (minter *minter) getTransactions() *types.TransactionsByPriceAndNonce { 289 allAddrTxes, err := minter.eth.TxPool().Pending() 290 if err != nil { // TODO: handle 291 panic(err) 292 } 293 addrTxes := minter.speculativeChain.withoutProposedTxes(allAddrTxes) 294 signer := types.MakeSigner(minter.chain.Config(), minter.chain.CurrentBlock().Number()) 295 return types.NewTransactionsByPriceAndNonce(signer, addrTxes) 296 } 297 298 // Sends-off events asynchronously. 299 func (minter *minter) firePendingBlockEvents(logs []*types.Log) { 300 // Copy logs before we mutate them, adding a block hash. 301 copiedLogs := make([]*types.Log, len(logs)) 302 for i, l := range logs { 303 copiedLogs[i] = new(types.Log) 304 *copiedLogs[i] = *l 305 } 306 307 go func() { 308 minter.eth.pendingLogsFeed.Send(copiedLogs) 309 minter.mux.Post(core.PendingStateEvent{}) 310 }() 311 } 312 313 func (minter *minter) mintNewBlock() { 314 minter.mu.Lock() 315 defer minter.mu.Unlock() 316 317 work := minter.createWork() 318 transactions := minter.getTransactions() 319 320 committedTxes, publicReceipts, _, logs := work.commitTransactions(transactions, minter.chain) 321 txCount := len(committedTxes) 322 323 if txCount == 0 { 324 log.Info("Not minting a new block since there are no pending transactions") 325 return 326 } 327 328 minter.firePendingBlockEvents(logs) 329 330 header := work.header 331 332 // commit state root after all state transitions. 333 ethash.AccumulateRewards(minter.chain.Config(), work.publicState, header, nil) 334 header.Root = work.publicState.IntermediateRoot(minter.chain.Config().IsEIP158(work.header.Number)) 335 336 // update block hash since it is now available, but was not when the 337 // receipt/log of individual transactions were created: 338 headerHash := header.Hash() 339 for _, l := range logs { 340 l.BlockHash = headerHash 341 } 342 343 //Sign the block and build the extraSeal struct 344 extraSealBytes := minter.buildExtraSeal(headerHash) 345 346 // add vanity and seal to header 347 // NOTE: leaving vanity blank for now as a space for any future data 348 header.Extra = make([]byte, extraVanity+len(extraSealBytes)) 349 copy(header.Extra[extraVanity:], extraSealBytes) 350 351 block := types.NewBlock(header, committedTxes, nil, publicReceipts, new(trie.Trie)) 352 353 log.Info("Generated next block", "block num", block.Number(), "num txes", txCount) 354 355 deleteEmptyObjects := minter.chain.Config().IsEIP158(block.Number()) 356 if err := minter.chain.CommitBlockWithState(deleteEmptyObjects, work.publicState, work.privateState); err != nil { 357 panic(err) 358 } 359 360 minter.speculativeChain.extend(block) 361 362 minter.mux.Post(core.NewMinedBlockEvent{Block: block}) 363 364 elapsed := time.Since(time.Unix(0, int64(header.Time))) 365 log.Info("🔨 Mined block", "number", block.Number(), "hash", fmt.Sprintf("%x", block.Hash().Bytes()[:4]), "elapsed", elapsed) 366 } 367 368 func (env *work) commitTransactions(txes *types.TransactionsByPriceAndNonce, bc *core.BlockChain) (types.Transactions, types.Receipts, types.Receipts, []*types.Log) { 369 var allLogs []*types.Log 370 var committedTxes types.Transactions 371 var publicReceipts types.Receipts 372 var privateReceipts types.Receipts 373 374 gp := new(core.GasPool).AddGas(env.header.GasLimit) 375 txCount := 0 376 377 for { 378 tx := txes.Peek() 379 if tx == nil { 380 break 381 } 382 383 env.publicState.Prepare(tx.Hash(), common.Hash{}, txCount) 384 385 publicReceipt, privateReceipt, err := env.commitTransaction(tx, bc, gp) 386 switch { 387 case err != nil: 388 log.Info("TX failed, will be removed", "hash", tx.Hash(), "err", err) 389 txes.Pop() // skip rest of txes from this account 390 default: 391 txCount++ 392 committedTxes = append(committedTxes, tx) 393 394 publicReceipts = append(publicReceipts, publicReceipt) 395 allLogs = append(allLogs, publicReceipt.Logs...) 396 397 if privateReceipt != nil { 398 privateReceipts = append(privateReceipts, privateReceipt) 399 allLogs = append(allLogs, privateReceipt.Logs...) 400 } 401 402 txes.Shift() 403 } 404 } 405 406 return committedTxes, publicReceipts, privateReceipts, allLogs 407 } 408 409 func (env *work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (*types.Receipt, *types.Receipt, error) { 410 publicSnapshot := env.publicState.Snapshot() 411 privateSnapshot := env.privateState.Snapshot() 412 413 var author *common.Address 414 var vmConf vm.Config 415 txnStart := time.Now() 416 // Note that raft minter doesn't care about private state etc, hence can pass forceNonParty=true and privateStateRepo=nil 417 publicReceipt, privateReceipt, err := core.ApplyTransaction(env.config, bc, author, gp, env.publicState, env.privateState, env.header, tx, &env.header.GasUsed, vmConf, true, nil) 418 if err != nil { 419 env.publicState.RevertToSnapshot(publicSnapshot) 420 env.privateState.RevertToSnapshot(privateSnapshot) 421 422 return nil, nil, err 423 } 424 log.EmitCheckpoint(log.TxCompleted, "tx", tx.Hash().Hex(), "time", time.Since(txnStart)) 425 426 return publicReceipt, privateReceipt, nil 427 } 428 429 func (minter *minter) buildExtraSeal(headerHash common.Hash) []byte { 430 //Sign the headerHash 431 nodeKey := minter.eth.nodeKey 432 sig, err := crypto.Sign(headerHash.Bytes(), nodeKey) 433 if err != nil { 434 log.Warn("Block sealing failed", "err", err) 435 } 436 437 //build the extraSeal struct 438 raftIdString := hexutil.EncodeUint64(uint64(minter.eth.raftProtocolManager.raftId)) 439 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 }