OSDN Git Service

rename (#465)
[bytom/vapor.git] / protocol / protocol.go
index 153312c..56c85fb 100644 (file)
@@ -5,15 +5,18 @@ import (
 
        log "github.com/sirupsen/logrus"
 
-       "github.com/vapor/common"
-       "github.com/vapor/config"
-       "github.com/vapor/event"
-       "github.com/vapor/protocol/bc"
-       "github.com/vapor/protocol/bc/types"
-       "github.com/vapor/protocol/state"
+       "github.com/bytom/vapor/common"
+       "github.com/bytom/vapor/config"
+       "github.com/bytom/vapor/event"
+       "github.com/bytom/vapor/protocol/bc"
+       "github.com/bytom/vapor/protocol/bc/types"
+       "github.com/bytom/vapor/protocol/state"
 )
 
-const maxProcessBlockChSize = 1024
+const (
+       maxProcessBlockChSize = 1024
+       maxKnownTxs           = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
+)
 
 // Chain provides functions for working with the Bytom block chain.
 type Chain struct {
@@ -26,12 +29,15 @@ type Chain struct {
        eventDispatcher *event.Dispatcher
 
        cond               sync.Cond
-       bestBlockHeader    *types.BlockHeader
-       bestIrrBlockHeader *types.BlockHeader
+       bestBlockHeader    *types.BlockHeader // the last block on current main chain
+       lastIrrBlockHeader *types.BlockHeader // the last irreversible block
+
+       knownTxs *common.OrderedSet
 }
 
 // NewChain returns a new Chain using store as the underlying storage.
 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
+       knownTxs, _ := common.NewOrderedSet(maxKnownTxs)
        c := &Chain{
                orphanManage:    NewOrphanManage(),
                txPool:          txPool,
@@ -39,6 +45,7 @@ func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*
                signatureCache:  common.NewCache(maxSignatureCacheSize),
                eventDispatcher: eventDispatcher,
                processBlockCh:  make(chan *processBlockMsg, maxProcessBlockChSize),
+               knownTxs:        knownTxs,
        }
        c.cond.L = new(sync.Mutex)
 
@@ -56,7 +63,7 @@ func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*
                return nil, err
        }
 
-       c.bestIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
+       c.lastIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
        if err != nil {
                return nil, err
        }
@@ -102,7 +109,7 @@ func (c *Chain) BestBlockHeight() uint64 {
        return c.bestBlockHeader.Height
 }
 
-// BestBlockHash return the hash of the chain tail block
+// BestBlockHash return the hash of the main chain tail block
 func (c *Chain) BestBlockHash() *bc.Hash {
        c.cond.L.Lock()
        defer c.cond.L.Unlock()
@@ -110,11 +117,11 @@ func (c *Chain) BestBlockHash() *bc.Hash {
        return &bestHash
 }
 
-// BestIrreversibleHeader returns the chain best irreversible block header
-func (c *Chain) BestIrreversibleHeader() *types.BlockHeader {
+// LastIrreversibleHeader returns the chain last irreversible block header
+func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
        c.cond.L.Lock()
        defer c.cond.L.Unlock()
-       return c.bestIrrBlockHeader
+       return c.lastIrrBlockHeader
 }
 
 // BestBlockHeader returns the chain best block header
@@ -139,6 +146,42 @@ func (c *Chain) InMainChain(hash bc.Hash) bool {
        return *blockHash == hash
 }
 
+// trace back to the tail of the chain from the given block header
+func (c *Chain) traceLongestChainTail(blockHeader *types.BlockHeader) (*types.BlockHeader, error) {
+       longestTail, workQueue := blockHeader, []*types.BlockHeader{blockHeader}
+
+       for ; len(workQueue) > 0; workQueue = workQueue[1:] {
+               currentHeader := workQueue[0]
+               currentHash := currentHeader.Hash()
+               hashes, err := c.store.GetBlockHashesByHeight(currentHeader.Height + 1)
+               if err != nil {
+                       return nil, err
+               }
+
+               for _, h := range hashes {
+                       if header, err := c.store.GetBlockHeader(h); err != nil {
+                               return nil, err
+                       } else if header.PreviousBlockHash == currentHash {
+                               if longestTail.Height < header.Height {
+                                       longestTail = header
+                               }
+                               workQueue = append(workQueue, header)
+                       }
+               }
+       }
+       return longestTail, nil
+}
+
+func (c *Chain) hasSeenTx(tx *types.Tx) bool {
+       return c.knownTxs.Has(tx.ID.String())
+}
+
+func (c *Chain) markTransactions(txs ...*types.Tx) {
+       for _, tx := range txs {
+               c.knownTxs.Add(tx.ID.String())
+       }
+}
+
 // This function must be called with mu lock in above level
 func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error {
        if err := c.store.SaveChainStatus(blockHeader, irrBlockHeader, mainBlockHeaders, view, consensusResults); err != nil {
@@ -146,7 +189,7 @@ func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlo
        }
 
        c.bestBlockHeader = blockHeader
-       c.bestIrrBlockHeader = irrBlockHeader
+       c.lastIrrBlockHeader = irrBlockHeader
 
        blockHash := blockHeader.Hash()
        log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("chain best status has been update")