github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/consensus/accept.go (about)

     1  package consensus
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"time"
    10  
    11  	"SiaPrime/modules"
    12  	"SiaPrime/types"
    13  
    14  	"gitlab.com/NebulousLabs/bolt"
    15  )
    16  
    17  var (
    18  	errDoSBlock        = errors.New("block is known to be invalid")
    19  	errInconsistentSet = errors.New("consensus set is not in a consistent state")
    20  	errNoBlockMap      = errors.New("block map is not in database")
    21  	errNonLinearChain  = errors.New("block set is not a contiguous chain")
    22  	errOrphan          = errors.New("block has no known parent")
    23  )
    24  
    25  // managedBroadcastBlock will broadcast a block to the consensus set's peers.
    26  func (cs *ConsensusSet) managedBroadcastBlock(b types.Block) {
    27  	// broadcast the block header to all peers
    28  	go cs.gateway.Broadcast("RelayHeader", b.Header(), cs.gateway.Peers())
    29  }
    30  
    31  // validateHeaderAndBlock does some early, low computation verification on the
    32  // block. Callers should not assume that validation will happen in a particular
    33  // order.
    34  func (cs *ConsensusSet) validateHeaderAndBlock(tx dbTx, b types.Block, id types.BlockID) (parent *processedBlock, err error) {
    35  	// Check if the block is a DoS block - a known invalid block that is expensive
    36  	// to validate.
    37  	_, exists := cs.dosBlocks[id]
    38  	if exists {
    39  		return nil, errDoSBlock
    40  	}
    41  
    42  	// Check if the block is already known.
    43  	blockMap := tx.Bucket(BlockMap)
    44  	if blockMap == nil {
    45  		return nil, errNoBlockMap
    46  	}
    47  	if blockMap.Get(id[:]) != nil {
    48  		return nil, modules.ErrBlockKnown
    49  	}
    50  
    51  	// Check for the parent.
    52  	parentID := b.ParentID
    53  	parentBytes := blockMap.Get(parentID[:])
    54  	if parentBytes == nil {
    55  		return nil, errOrphan
    56  	}
    57  	parent = new(processedBlock)
    58  	err = cs.marshaler.Unmarshal(parentBytes, parent)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	// Check that the timestamp is not too far in the past to be acceptable.
    63  	minTimestamp := cs.blockRuleHelper.minimumValidChildTimestamp(blockMap, parent)
    64  
    65  	// XXX debugging
    66  	var payoutSum types.Currency
    67  	for _, payout := range b.MinerPayouts {
    68  		//if payout.Value.IsZero() {
    69  		//        return false
    70  		//}
    71  		payoutSum = payoutSum.Add(payout.Value)
    72  	}
    73  	// cs.log.Debugln(fmt.Sprintf("block id: %s, #txs: %d, miner fees %s, miner subsidy (calculated by transaction fees): %s miner payout: %s\n", b.ID(), len(b.Transactions), b.CalculateMinerFees().String(), b.CalculateSubsidy(parent.Height+1).String(), payoutSum.String()))
    74  	// XXX debugging
    75  
    76  	err = cs.blockValidator.ValidateBlock(b, id, minTimestamp, parent.ChildTarget, parent.Height+1, cs.log)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	return parent, nil
    81  }
    82  
    83  // checkHeaderTarget returns true if the header's ID meets the given target.
    84  func checkHeaderTarget(h types.BlockHeader, target types.Target) bool {
    85  	blockHash := h.ID()
    86  	return bytes.Compare(target[:], blockHash[:]) >= 0
    87  }
    88  
    89  // validateHeader does some early, low computation verification on the header
    90  // to determine if the block should be downloaded. Callers should not assume
    91  // that validation will happen in a particular order.
    92  func (cs *ConsensusSet) validateHeader(tx dbTx, h types.BlockHeader) error {
    93  	// Check if the block is a DoS block - a known invalid block that is expensive
    94  	// to validate.
    95  	id := h.ID()
    96  	_, exists := cs.dosBlocks[id]
    97  	if exists {
    98  		return errDoSBlock
    99  	}
   100  
   101  	// Check if the block is already known.
   102  	blockMap := tx.Bucket(BlockMap)
   103  	if blockMap == nil {
   104  		return errNoBlockMap
   105  	}
   106  	if blockMap.Get(id[:]) != nil {
   107  		return modules.ErrBlockKnown
   108  	}
   109  
   110  	// Check for the parent.
   111  	parentID := h.ParentID
   112  	parentBytes := blockMap.Get(parentID[:])
   113  	if parentBytes == nil {
   114  		return errOrphan
   115  	}
   116  	var parent processedBlock
   117  	err := cs.marshaler.Unmarshal(parentBytes, &parent)
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	// Check that the nonce is a legal nonce.
   123  	//
   124  	// It's parentHeight > types.ASICHardforkHeight, because in another place in
   125  	// the code we use 'height >= types.ASICHardforkHeight'. This keeps the
   126  	// trigger on the same block.
   127  	if parent.Height > types.ASICHardforkHeight && binary.LittleEndian.Uint64(h.Nonce[:])%types.ASICHardforkFactor != 0 {
   128  		return errors.New("block does not meet nonce requirements")
   129  	}
   130  	// Check that the target of the new block is sufficient.
   131  	if !checkHeaderTarget(h, parent.ChildTarget) {
   132  		return modules.ErrBlockUnsolved
   133  	}
   134  
   135  	// TODO: check if the block is a non extending block once headers-first
   136  	// downloads are implemented.
   137  
   138  	// Check that the timestamp is not too far in the past to be acceptable.
   139  	minTimestamp := cs.blockRuleHelper.minimumValidChildTimestamp(blockMap, &parent)
   140  	if minTimestamp > h.Timestamp {
   141  		return errEarlyTimestamp
   142  	}
   143  
   144  	// Check if the block is in the extreme future. We make a distinction between
   145  	// future and extreme future because there is an assumption that by the time
   146  	// the extreme future arrives, this block will no longer be a part of the
   147  	// longest fork because it will have been ignored by all of the miners.
   148  	if h.Timestamp > types.CurrentTimestamp()+types.ExtremeFutureThreshold {
   149  		return errExtremeFutureTimestamp
   150  	}
   151  
   152  	// We do not check if the header is in the near future here, because we want
   153  	// to get the corresponding block as soon as possible, even if the block is in
   154  	// the near future.
   155  
   156  	return nil
   157  }
   158  
   159  // addBlockToTree inserts a block into the blockNode tree by adding it to its
   160  // parent's list of children. If the new blockNode is heavier than the current
   161  // node, the blockchain is forked to put the new block and its parents at the
   162  // tip. An error will be returned if block verification fails or if the block
   163  // does not extend the longest fork.
   164  //
   165  // addBlockToTree might need to modify the database while returning an error
   166  // on the block. Such errors are handled outside of the transaction by the
   167  // caller. Switching to a managed tx through bolt will make this complexity
   168  // unneeded.
   169  func (cs *ConsensusSet) addBlockToTree(tx *bolt.Tx, b types.Block, parent *processedBlock) (ce changeEntry, err error) {
   170  	// Prepare the child processed block associated with the parent block.
   171  	newNode := cs.newChild(tx, parent, b)
   172  
   173  	// Check whether the new node is part of a chain that is heavier than the
   174  	// current node. If not, return ErrNonExtending and don't fork the
   175  	// blockchain.
   176  	currentNode := currentProcessedBlock(tx)
   177  	if !newNode.heavierThan(currentNode) {
   178  		return changeEntry{}, modules.ErrNonExtendingBlock
   179  	}
   180  
   181  	// Fork the blockchain and put the new heaviest block at the tip of the
   182  	// chain.
   183  	var revertedBlocks, appliedBlocks []*processedBlock
   184  	revertedBlocks, appliedBlocks, err = cs.forkBlockchain(tx, newNode)
   185  	if err != nil {
   186  		return changeEntry{}, err
   187  	}
   188  	for _, rn := range revertedBlocks {
   189  		ce.RevertedBlocks = append(ce.RevertedBlocks, rn.Block.ID())
   190  	}
   191  	for _, an := range appliedBlocks {
   192  		ce.AppliedBlocks = append(ce.AppliedBlocks, an.Block.ID())
   193  	}
   194  	err = appendChangeLog(tx, ce)
   195  	if err != nil {
   196  		return changeEntry{}, err
   197  	}
   198  	return ce, nil
   199  }
   200  
   201  // threadedSleepOnFutureBlock will sleep until the timestamp of a future block
   202  // has arrived.
   203  //
   204  // TODO: An attacker can broadcast a future block multiple times, resulting in a
   205  // goroutine spinup for each future block.  Need to prevent that.
   206  //
   207  // TODO: An attacker could produce a very large number of future blocks,
   208  // consuming memory. Need to prevent that.
   209  func (cs *ConsensusSet) threadedSleepOnFutureBlock(b types.Block) {
   210  	// Add this thread to the threadgroup.
   211  	err := cs.tg.Add()
   212  	if err != nil {
   213  		return
   214  	}
   215  	defer cs.tg.Done()
   216  
   217  	// Perform a soft-sleep while we wait for the block to become valid.
   218  	select {
   219  	case <-cs.tg.StopChan():
   220  		return
   221  	case <-time.After(time.Duration(b.Timestamp-(types.CurrentTimestamp()+types.FutureThreshold)) * time.Second):
   222  		_, err := cs.managedAcceptBlocks([]types.Block{b})
   223  		if err != nil {
   224  			cs.log.Debugln("WARN: failed to accept a future block:", err)
   225  		}
   226  		cs.managedBroadcastBlock(b)
   227  	}
   228  }
   229  
   230  // managedAcceptBlocks will try to add blocks to the consensus set. If the
   231  // blocks do not extend the longest currently known chain, an error is
   232  // returned but the blocks are still kept in memory. If the blocks extend a fork
   233  // such that the fork becomes the longest currently known chain, the consensus
   234  // set will reorganize itself to recognize the new longest fork. Accepted
   235  // blocks are not relayed.
   236  //
   237  // Typically AcceptBlock should be used so that the accepted block is relayed.
   238  // This method is typically only be used when there would otherwise be multiple
   239  // consecutive calls to AcceptBlock with each successive call accepting the
   240  // child block of the previous call.
   241  func (cs *ConsensusSet) managedAcceptBlocks(blocks []types.Block) (blockchainExtended bool, err error) {
   242  	// Grab a lock on the consensus set.
   243  	cs.mu.Lock()
   244  	defer cs.mu.Unlock()
   245  
   246  	// Make sure that blocks are consecutive. Though this isn't a strict
   247  	// requirement, if blocks are not consecutive then it becomes a lot harder
   248  	// to maintain correcetness when adding multiple blocks in a single tx.
   249  	//
   250  	// This is the first time that IDs on the blocks have been computed.
   251  	blockIDs := make([]types.BlockID, 0, len(blocks))
   252  	for i := 0; i < len(blocks); i++ {
   253  		blockIDs = append(blockIDs, blocks[i].ID())
   254  		if i > 0 && blocks[i].ParentID != blockIDs[i-1] {
   255  			return false, errNonLinearChain
   256  		}
   257  	}
   258  
   259  	// Verify the headers for every block, throw out known blocks, and the
   260  	// invalid blocks (which includes the children of invalid blocks).
   261  	chainExtended := false
   262  	changes := make([]changeEntry, 0, len(blocks))
   263  	setErr := cs.db.Update(func(tx *bolt.Tx) error {
   264  		for i := 0; i < len(blocks); i++ {
   265  			// Start by checking the header of the block.
   266  			parent, err := cs.validateHeaderAndBlock(boltTxWrapper{tx}, blocks[i], blockIDs[i])
   267  			if err == modules.ErrBlockKnown {
   268  				// Skip over known blocks.
   269  				continue
   270  			}
   271  			if err == errFutureTimestamp {
   272  				// Queue the block to be tried again if it is a future block.
   273  				go cs.threadedSleepOnFutureBlock(blocks[i])
   274  			}
   275  			if err != nil {
   276  				return err
   277  			}
   278  
   279  			// Try adding the block to consensus.
   280  			changeEntry, err := cs.addBlockToTree(tx, blocks[i], parent)
   281  			if err == nil {
   282  				changes = append(changes, changeEntry)
   283  				chainExtended = true
   284  				var applied, reverted []string
   285  				for _, b := range changeEntry.AppliedBlocks {
   286  					applied = append(applied, b.String()[:6])
   287  				}
   288  				for _, b := range changeEntry.RevertedBlocks {
   289  					reverted = append(reverted, b.String()[:6])
   290  				}
   291  			}
   292  			if err == modules.ErrNonExtendingBlock {
   293  				err = nil
   294  			}
   295  			if err != nil {
   296  				return err
   297  			}
   298  			// Sanity check - we should never apply fewer blocks than we revert.
   299  			if len(changeEntry.AppliedBlocks) < len(changeEntry.RevertedBlocks) {
   300  				err := errors.New("after adding a change entry, there are more reverted blocks than applied ones")
   301  				cs.log.Severe(err)
   302  				return err
   303  			}
   304  		}
   305  		return nil
   306  	})
   307  	if _, ok := setErr.(bolt.MmapError); ok {
   308  		cs.log.Println("ERROR: Bolt mmap failed:", setErr)
   309  		fmt.Println("Blockchain database has run out of disk space!")
   310  		os.Exit(1)
   311  	}
   312  	if setErr != nil {
   313  		if len(changes) == 0 {
   314  			cs.log.Println("Consensus received an invalid block:", setErr)
   315  		} else {
   316  			fmt.Println("Received a partially valid block set.")
   317  			cs.log.Println("Consensus received a chain of blocks, where one was valid, but others were not:", setErr)
   318  		}
   319  		return false, setErr
   320  	}
   321  	// Stop here if the blocks did not extend the longest blockchain.
   322  	if !chainExtended {
   323  		return false, modules.ErrNonExtendingBlock
   324  	}
   325  	// Send any changes to subscribers.
   326  	for i := 0; i < len(changes); i++ {
   327  		cs.updateSubscribers(changes[i])
   328  	}
   329  	return chainExtended, nil
   330  }
   331  
   332  // AcceptBlock will try to add a block to the consensus set. If the block does
   333  // not extend the longest currently known chain, an error is returned but the
   334  // block is still kept in memory. If the block extends a fork such that the
   335  // fork becomes the longest currently known chain, the consensus set will
   336  // reorganize itself to recognize the new longest fork. If a block is accepted
   337  // without error, it will be relayed to all connected peers. This function
   338  // should only be called for new blocks.
   339  func (cs *ConsensusSet) AcceptBlock(b types.Block) error {
   340  	err := cs.tg.Add()
   341  	if err != nil {
   342  		return err
   343  	}
   344  	defer cs.tg.Done()
   345  
   346  	chainExtended, err := cs.managedAcceptBlocks([]types.Block{b})
   347  	if err != nil {
   348  		return err
   349  	}
   350  	if chainExtended {
   351  		cs.managedBroadcastBlock(b)
   352  	}
   353  	return nil
   354  }