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  }