neo-go/pkg/core/blockchain_test.go
Vsevolod Brekelov ec17654986 core: refactoring blockchain state and storage
add dao which takes care about all CRUD operations on storage
remove blockchain state since everything is stored on change
remove storage operations from structs(entities)
move structs to entities package
2019-12-11 13:05:31 +03:00

177 lines
4.5 KiB
Go

package core
import (
"testing"
"github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAddHeaders(t *testing.T) {
bc := newTestChain(t)
h1 := newBlock(1).Header()
h2 := newBlock(2).Header()
h3 := newBlock(3).Header()
if err := bc.AddHeaders(h1, h2, h3); err != nil {
t.Fatal(err)
}
assert.Equal(t, h3.Index, bc.HeaderHeight())
assert.Equal(t, uint32(0), bc.BlockHeight())
assert.Equal(t, h3.Hash(), bc.CurrentHeaderHash())
// Add them again, they should not be added.
if err := bc.AddHeaders(h3, h2, h1); err != nil {
t.Fatal(err)
}
assert.Equal(t, h3.Index, bc.HeaderHeight())
assert.Equal(t, uint32(0), bc.BlockHeight())
assert.Equal(t, h3.Hash(), bc.CurrentHeaderHash())
}
func TestAddBlock(t *testing.T) {
bc := newTestChain(t)
blocks := []*Block{
newBlock(1, newMinerTX()),
newBlock(2, newMinerTX()),
newBlock(3, newMinerTX()),
}
for i := 0; i < len(blocks); i++ {
if err := bc.AddBlock(blocks[i]); err != nil {
t.Fatal(err)
}
}
lastBlock := blocks[len(blocks)-1]
assert.Equal(t, lastBlock.Index, bc.HeaderHeight())
assert.Equal(t, lastBlock.Hash(), bc.CurrentHeaderHash())
// This one tests persisting blocks, so it does need to persist()
require.NoError(t, bc.persist())
for _, block := range blocks {
key := storage.AppendPrefix(storage.DataBlock, block.Hash().BytesLE())
if _, err := bc.dao.store.Get(key); err != nil {
t.Fatalf("block %s not persisted", block.Hash())
}
}
assert.Equal(t, lastBlock.Index, bc.BlockHeight())
assert.Equal(t, lastBlock.Hash(), bc.CurrentHeaderHash())
}
func TestGetHeader(t *testing.T) {
bc := newTestChain(t)
block := newBlock(1, newMinerTX())
err := bc.AddBlock(block)
assert.Nil(t, err)
// Test unpersisted and persisted access
for i := 0; i < 2; i++ {
hash := block.Hash()
header, err := bc.GetHeader(hash)
require.NoError(t, err)
assert.Equal(t, block.Header(), header)
b2 := newBlock(2)
_, err = bc.GetHeader(b2.Hash())
assert.Error(t, err)
assert.NoError(t, bc.persist())
}
}
func TestGetBlock(t *testing.T) {
bc := newTestChain(t)
blocks := makeBlocks(100)
for i := 0; i < len(blocks); i++ {
if err := bc.AddBlock(blocks[i]); err != nil {
t.Fatal(err)
}
}
// Test unpersisted and persisted access
for j := 0; j < 2; j++ {
for i := 0; i < len(blocks); i++ {
block, err := bc.GetBlock(blocks[i].Hash())
if err != nil {
t.Fatalf("can't get block %d: %s, attempt %d", i, err, j)
}
assert.Equal(t, blocks[i].Index, block.Index)
assert.Equal(t, blocks[i].Hash(), block.Hash())
}
assert.NoError(t, bc.persist())
}
}
func TestHasBlock(t *testing.T) {
bc := newTestChain(t)
blocks := makeBlocks(50)
for i := 0; i < len(blocks); i++ {
if err := bc.AddBlock(blocks[i]); err != nil {
t.Fatal(err)
}
}
// Test unpersisted and persisted access
for j := 0; j < 2; j++ {
for i := 0; i < len(blocks); i++ {
assert.True(t, bc.HasBlock(blocks[i].Hash()))
}
newBlock := newBlock(51)
assert.False(t, bc.HasBlock(newBlock.Hash()))
assert.NoError(t, bc.persist())
}
}
func TestGetTransaction(t *testing.T) {
b1 := getDecodedBlock(t, 1)
block := getDecodedBlock(t, 2)
bc := newTestChain(t)
// Turn verification off, because these blocks are really from some other chain
// and can't be verified, but we don't care about that in this test.
bc.config.VerifyBlocks = false
assert.Nil(t, bc.AddBlock(b1))
assert.Nil(t, bc.AddBlock(block))
// Test unpersisted and persisted access
for j := 0; j < 2; j++ {
tx, height, err := bc.GetTransaction(block.Transactions[0].Hash())
require.Nil(t, err)
assert.Equal(t, block.Index, height)
assert.Equal(t, block.Transactions[0], tx)
assert.Equal(t, 10, io.GetVarSize(tx))
assert.Equal(t, 1, io.GetVarSize(tx.Attributes))
assert.Equal(t, 1, io.GetVarSize(tx.Inputs))
assert.Equal(t, 1, io.GetVarSize(tx.Outputs))
assert.Equal(t, 1, io.GetVarSize(tx.Scripts))
assert.NoError(t, bc.persist())
}
}
func TestClose(t *testing.T) {
defer func() {
r := recover()
assert.NotNil(t, r)
}()
bc := newTestChain(t)
blocks := makeBlocks(10)
for i := 0; i < len(blocks); i++ {
require.NoError(t, bc.AddBlock(blocks[i]))
}
bc.Close()
// It's a hack, but we use internal knowledge of MemoryStore
// implementation which makes it completely unusable (up to panicing)
// after Close().
_ = bc.dao.store.Put([]byte{0}, []byte{1})
// This should never be executed.
assert.Nil(t, t)
}