aergoio/aergo

View on GitHub
chain/stubchain.go

Summary

Maintainability
A
1 hr
Test Coverage
F
28%
package chain

import (
    "bytes"
    "errors"
    "math/big"
    "time"

    "github.com/aergoio/aergo/v2/types"
    "github.com/aergoio/aergo/v2/types/message"
)

// StubSyncer receive Syncer, P2P, Chain Service actor message
type StubBlockChain struct {
    Best   int
    Hashes []([]byte)
    Blocks []*types.Block

    BestBlock *types.Block
}

var _ types.ChainAccessor = (*StubBlockChain)(nil)

var (
    ErrNotExistHash  = errors.New("not exist hash")
    ErrNotExistBlock = errors.New("not exist block of the hash")

    testBV = types.DummyBlockVersionner(0)
)

func NewStubBlockChain(size int) *StubBlockChain {
    if size < 10000 {
        size = 10000
    }

    tchain := &StubBlockChain{Best: -1}

    tchain.Hashes = make([][]byte, size+1)
    tchain.Blocks = make([]*types.Block, size+1)

    return tchain
}

func (tchain *StubBlockChain) GenAddBlock() {
    var bi *types.BlockHeaderInfo
    var prevBlockRootHash []byte
    if tchain.BestBlock != nil {
        bi = types.NewBlockHeaderInfoFromPrevBlock(tchain.BestBlock, time.Now().UnixNano(), types.DummyBlockVersionner(0))
        prevBlockRootHash = tchain.BestBlock.GetHeader().BlocksRootHash
    } else {
        cid, _ := types.NewChainID().Bytes()
        bi = &types.BlockHeaderInfo{Ts: time.Now().UnixNano(), ChainId: cid}
    }
    bi.Ts = time.Now().UnixNano()
    newBlock := types.NewBlock(bi, prevBlockRootHash, nil, nil, nil, nil)
    tchain.AddBlock(newBlock)
    time.Sleep(time.Nanosecond * 3)
}

func (tchain *StubBlockChain) AddBlock(newBlock *types.Block) error {
    if newBlock.BlockNo() != uint64(tchain.Best+1) {
        return ErrBlockOrphan
    }
    tchain.Best += 1
    tchain.Hashes[tchain.Best] = newBlock.BlockHash()
    tchain.Blocks[tchain.Best] = newBlock
    tchain.BestBlock = newBlock

    return nil
}

func (tchain *StubBlockChain) GetHashes(prevInfo *types.BlockInfo, count uint64) ([]message.BlockHash, error) {
    if tchain.Best < int(prevInfo.No+count) {
        return nil, ErrNotExistHash
    }

    start := prevInfo.No + 1
    resHashes := tchain.Hashes[start : start+count]

    blkHashes := make([]message.BlockHash, 0)
    for _, hash := range resHashes {
        blkHashes = append(blkHashes, hash)
    }

    return blkHashes, nil
}

func (tchain *StubBlockChain) GetBlockInfo(no uint64) *types.BlockInfo {
    return &types.BlockInfo{Hash: tchain.Hashes[no], No: no}
}

func (tchain *StubBlockChain) GetBlockByNo(no uint64) *types.Block {
    return tchain.Blocks[no]
}

func (tchain *StubBlockChain) GetBlocks(hashes []message.BlockHash) ([]*types.Block, error) {
    startNo := -1

    for i, block := range tchain.Blocks {
        if bytes.Equal(block.GetHash(), hashes[0]) {
            startNo = i
            break
        }
    }

    if startNo == -1 {
        return nil, ErrNotExistBlock
    }

    resultBlocks := make([]*types.Block, 0)
    i := startNo
    for _, hash := range hashes {
        if !bytes.Equal(tchain.Blocks[i].GetHash(), hash) {
            return nil, ErrNotExistBlock
        }

        resultBlocks = append(resultBlocks, tchain.Blocks[i])
        i++
    }

    return resultBlocks, nil
}

func (tchain *StubBlockChain) GetGenesisInfo() *types.Genesis {
    // Not implemented. It should be implemented later if any test is related
    // to genesis info.
    return nil
}

func (tchain *StubBlockChain) GetConsensusInfo() string {
    return ""
}

func (tchain *StubBlockChain) GetChainStats() string {
    return ""
}

func (tchain *StubBlockChain) GetSystemValue(key types.SystemValue) (*big.Int, error) {
    return nil, nil
}

func (tchain *StubBlockChain) GetEnterpriseConfig(key string) (*types.EnterpriseConfig, error) {
    return nil, nil
}

func (tchain *StubBlockChain) GetBestBlock() (*types.Block, error) {
    return tchain.BestBlock, nil
}

func (tchain *StubBlockChain) GetBlock(blockHash []byte) (*types.Block, error) {
    for _, block := range tchain.Blocks {
        if bytes.Equal(block.GetHash(), blockHash) {
            return block, nil
        }
    }

    return nil, ErrNotExistBlock
}

func (tchain *StubBlockChain) GetHashByNo(blockNo types.BlockNo) ([]byte, error) {
    if uint64(len(tchain.Hashes)) <= blockNo {
        return nil, ErrNotExistHash
    }

    return tchain.Hashes[blockNo], nil
}

// TODO refactoring with getAnchorsNew()
func (tchain *StubBlockChain) GetAnchors() (ChainAnchor, types.BlockNo, error) {
    //from top : 8 * 32 = 256
    anchors := make(ChainAnchor, 0)
    cnt := MaxAnchors
    logger.Debug().Msg("get anchors")

    bestBlock, _ := tchain.GetBestBlock()
    blkNo := bestBlock.BlockNo()
    var lastNo types.BlockNo
LOOP:
    for i := 0; i < cnt; i++ {
        blockHash, err := tchain.GetHashByNo(blkNo)
        if err != nil {
            logger.Info().Msg("assertion - hash get failed")
            // assertion!
            return nil, 0, err
        }

        anchors = append(anchors, blockHash)
        lastNo = blkNo

        logger.Debug().Uint64("no", blkNo).Msg("anchor added")

        switch {
        case blkNo == 0:
            break LOOP
        case blkNo < Skip:
            blkNo = 0
        default:
            blkNo -= Skip
        }
    }

    return anchors, lastNo, nil
}

func (tchain *StubBlockChain) GetAncestorWithHashes(hashes [][]byte) *types.BlockInfo {
    for _, hash := range hashes {
        for j, chainHash := range tchain.Hashes {
            if bytes.Equal(hash, chainHash) {
                return &types.BlockInfo{Hash: chainHash, No: uint64(j)}
            }
        }
    }

    return nil
}

func (tchain *StubBlockChain) ChainID(bno types.BlockNo) *types.ChainID {
    return nil
}

func (tchain *StubBlockChain) Rollback(ancestor *types.BlockInfo) {
    prevBest := tchain.Best
    tchain.Best = int(ancestor.No)
    tchain.BestBlock = tchain.Blocks[tchain.Best]

    logger.Debug().Int("prev", prevBest).Int("Best", tchain.Best).Msg("test local chain is rollbacked")
}

func InitStubBlockChain(prefixChain []*types.Block, genCount int) *StubBlockChain {
    newChain := NewStubBlockChain(genCount + len(prefixChain) + 1)

    //load initial Blocks
    for _, block := range prefixChain {
        newChain.AddBlock(block)
    }

    for i := 0; i < genCount; i++ {
        newChain.GenAddBlock()
    }

    return newChain
}