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  }