github.com/aergoio/aergo@v1.3.1/chain/stubchain.go (about)

     1  package chain
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"math/big"
     7  	"time"
     8  
     9  	"github.com/aergoio/aergo/message"
    10  	"github.com/aergoio/aergo/types"
    11  )
    12  
    13  //StubSyncer receive Syncer, P2P, Chain Service actor message
    14  type StubBlockChain struct {
    15  	Best   int
    16  	Hashes []([]byte)
    17  	Blocks []*types.Block
    18  
    19  	BestBlock *types.Block
    20  }
    21  
    22  var (
    23  	ErrNotExistHash  = errors.New("not exist hash")
    24  	ErrNotExistBlock = errors.New("not exist block of the hash")
    25  )
    26  
    27  func NewStubBlockChain(size int) *StubBlockChain {
    28  	if size < 10000 {
    29  		size = 10000
    30  	}
    31  
    32  	tchain := &StubBlockChain{Best: -1}
    33  
    34  	tchain.Hashes = make([][]byte, size+1)
    35  	tchain.Blocks = make([]*types.Block, size+1)
    36  
    37  	return tchain
    38  }
    39  
    40  func (tchain *StubBlockChain) GenAddBlock() {
    41  	var prevBlockRootHash []byte
    42  	if tchain.BestBlock != nil {
    43  		prevBlockRootHash = tchain.BestBlock.GetHeader().BlocksRootHash
    44  	}
    45  
    46  	newBlock := types.NewBlock(tchain.BestBlock, prevBlockRootHash, nil, nil, nil, time.Now().UnixNano())
    47  	tchain.AddBlock(newBlock)
    48  
    49  	time.Sleep(time.Nanosecond * 3)
    50  }
    51  
    52  func (tchain *StubBlockChain) AddBlock(newBlock *types.Block) error {
    53  	if newBlock.BlockNo() != uint64(tchain.Best+1) {
    54  		return ErrBlockOrphan
    55  	}
    56  	tchain.Best += 1
    57  	tchain.Hashes[tchain.Best] = newBlock.BlockHash()
    58  	tchain.Blocks[tchain.Best] = newBlock
    59  	tchain.BestBlock = newBlock
    60  
    61  	return nil
    62  }
    63  
    64  func (tchain *StubBlockChain) GetHashes(prevInfo *types.BlockInfo, count uint64) ([]message.BlockHash, error) {
    65  	if tchain.Best < int(prevInfo.No+count) {
    66  		return nil, ErrNotExistHash
    67  	}
    68  
    69  	start := prevInfo.No + 1
    70  	resHashes := tchain.Hashes[start : start+count]
    71  
    72  	blkHashes := make([]message.BlockHash, 0)
    73  	for _, hash := range resHashes {
    74  		blkHashes = append(blkHashes, hash)
    75  	}
    76  
    77  	return blkHashes, nil
    78  }
    79  
    80  func (tchain *StubBlockChain) GetBlockInfo(no uint64) *types.BlockInfo {
    81  	return &types.BlockInfo{tchain.Hashes[no], no}
    82  }
    83  
    84  func (tchain *StubBlockChain) GetBlockByNo(no uint64) *types.Block {
    85  	return tchain.Blocks[no]
    86  }
    87  
    88  func (tchain *StubBlockChain) GetBlocks(hashes []message.BlockHash) ([]*types.Block, error) {
    89  	startNo := -1
    90  
    91  	for i, block := range tchain.Blocks {
    92  		if bytes.Equal(block.GetHash(), hashes[0]) {
    93  			startNo = i
    94  			break
    95  		}
    96  	}
    97  
    98  	if startNo == -1 {
    99  		return nil, ErrNotExistBlock
   100  	}
   101  
   102  	resultBlocks := make([]*types.Block, 0)
   103  	i := startNo
   104  	for _, hash := range hashes {
   105  		if !bytes.Equal(tchain.Blocks[i].GetHash(), hash) {
   106  			return nil, ErrNotExistBlock
   107  		}
   108  
   109  		resultBlocks = append(resultBlocks, tchain.Blocks[i])
   110  		i++
   111  	}
   112  
   113  	return resultBlocks, nil
   114  }
   115  
   116  func (tchain *StubBlockChain) GetGenesisInfo() *types.Genesis {
   117  	// Not implemented. It should be implemented later if any test is related
   118  	// to genesis info.
   119  	return nil
   120  }
   121  
   122  func (tchain *StubBlockChain) GetConsensusInfo() string {
   123  	return ""
   124  }
   125  
   126  func (tchain *StubBlockChain) GetChainStats() string {
   127  	return ""
   128  }
   129  
   130  func (tchain *StubBlockChain) GetSystemValue(key types.SystemValue) (*big.Int, error) {
   131  	return nil, nil
   132  }
   133  
   134  func (tchain *StubBlockChain) GetEnterpriseConfig(key string) (*types.EnterpriseConfig, error) {
   135  	return nil, nil
   136  }
   137  
   138  func (tchain *StubBlockChain) GetBestBlock() (*types.Block, error) {
   139  	return tchain.BestBlock, nil
   140  }
   141  
   142  func (tchain *StubBlockChain) GetBlock(blockHash []byte) (*types.Block, error) {
   143  	for _, block := range tchain.Blocks {
   144  		if bytes.Equal(block.GetHash(), blockHash) {
   145  			return block, nil
   146  			break
   147  		}
   148  	}
   149  
   150  	return nil, ErrNotExistBlock
   151  }
   152  
   153  func (tchain *StubBlockChain) GetHashByNo(blockNo types.BlockNo) ([]byte, error) {
   154  	if uint64(len(tchain.Hashes)) <= blockNo {
   155  		return nil, ErrNotExistHash
   156  	}
   157  
   158  	return tchain.Hashes[blockNo], nil
   159  }
   160  
   161  //TODO refactoring with getAnchorsNew()
   162  func (tchain *StubBlockChain) GetAnchors() (ChainAnchor, types.BlockNo, error) {
   163  	//from top : 8 * 32 = 256
   164  	anchors := make(ChainAnchor, 0)
   165  	cnt := MaxAnchors
   166  	logger.Debug().Msg("get anchors")
   167  
   168  	bestBlock, _ := tchain.GetBestBlock()
   169  	blkNo := bestBlock.BlockNo()
   170  	var lastNo types.BlockNo
   171  LOOP:
   172  	for i := 0; i < cnt; i++ {
   173  		blockHash, err := tchain.GetHashByNo(blkNo)
   174  		if err != nil {
   175  			logger.Info().Msg("assertion - hash get failed")
   176  			// assertion!
   177  			return nil, 0, err
   178  		}
   179  
   180  		anchors = append(anchors, blockHash)
   181  		lastNo = blkNo
   182  
   183  		logger.Debug().Uint64("no", blkNo).Msg("anchor added")
   184  
   185  		switch {
   186  		case blkNo == 0:
   187  			break LOOP
   188  		case blkNo < Skip:
   189  			blkNo = 0
   190  		default:
   191  			blkNo -= Skip
   192  		}
   193  	}
   194  
   195  	return anchors, lastNo, nil
   196  }
   197  
   198  func (tchain *StubBlockChain) GetAncestorWithHashes(hashes [][]byte) *types.BlockInfo {
   199  	for _, hash := range hashes {
   200  		for j, chainHash := range tchain.Hashes {
   201  			if bytes.Equal(hash, chainHash) {
   202  				return &types.BlockInfo{Hash: chainHash, No: uint64(j)}
   203  			}
   204  		}
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  func (tchain *StubBlockChain) Rollback(ancestor *types.BlockInfo) {
   211  	prevBest := tchain.Best
   212  	tchain.Best = int(ancestor.No)
   213  	tchain.BestBlock = tchain.Blocks[tchain.Best]
   214  
   215  	logger.Debug().Int("prev", prevBest).Int("Best", tchain.Best).Msg("test local chain is rollbacked")
   216  }
   217  
   218  func InitStubBlockChain(prefixChain []*types.Block, genCount int) *StubBlockChain {
   219  	newChain := NewStubBlockChain(genCount + len(prefixChain) + 1)
   220  
   221  	//load initial Blocks
   222  	for _, block := range prefixChain {
   223  		newChain.AddBlock(block)
   224  	}
   225  
   226  	for i := 0; i < genCount; i++ {
   227  		newChain.GenAddBlock()
   228  	}
   229  
   230  	return newChain
   231  }