Lite wallet server https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

235 lines
4.8 KiB

package storage
import (
"context"
"database/sql"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"testing"
"time"
"github.com/golang/protobuf/proto"
_ "github.com/mattn/go-sqlite3"
"github.com/pkg/errors"
"github.com/zcash-hackworks/lightwalletd/parser"
"github.com/zcash-hackworks/lightwalletd/walletrpc"
)
type compactTest struct {
BlockHeight int `json:"block"`
BlockHash string `json:"hash"`
Full string `json:"full"`
Compact string `json:"compact"`
}
var compactTests []compactTest
func TestSqliteStorage(t *testing.T) {
blockJSON, err := ioutil.ReadFile("../testdata/compact_blocks.json")
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(blockJSON, &compactTests)
if err != nil {
t.Fatal(err)
}
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
// Fill tables
{
err = CreateTables(db)
if err != nil {
t.Fatal(err)
}
for _, test := range compactTests {
blockData, _ := hex.DecodeString(test.Full)
block := parser.NewBlock()
blockData, err = block.ParseFromSlice(blockData)
if err != nil {
t.Error(errors.Wrap(err, fmt.Sprintf("parsing testnet block %d", test.BlockHeight)))
continue
}
height := block.GetHeight()
hash := hex.EncodeToString(block.GetEncodableHash())
hasSapling := block.HasSaplingTransactions()
protoBlock := block.ToCompact()
marshaled, _ := proto.Marshal(protoBlock)
err = StoreBlock(db, height, hash, hasSapling, marshaled)
if err != nil {
t.Error(err)
continue
}
}
}
// Count the blocks
{
var count int
countBlocks := "SELECT count(*) FROM blocks"
err = db.QueryRow(countBlocks).Scan(&count)
if err != nil {
t.Error(errors.Wrap(err, fmt.Sprintf("counting compact blocks")))
}
if count != len(compactTests) {
t.Errorf("Wrong row count, want %d got %d", len(compactTests), count)
}
}
ctx := context.Background()
// Check height state is as expected
{
blockHeight, err := GetCurrentHeight(ctx, db)
if err != nil {
t.Error(errors.Wrap(err, fmt.Sprintf("checking current block height")))
}
lastBlockTest := compactTests[len(compactTests)-1]
if blockHeight != lastBlockTest.BlockHeight {
t.Errorf("Wrong block height, got: %d", blockHeight)
}
storedBlock, err := GetBlock(ctx, db, blockHeight)
if err != nil {
t.Error(errors.Wrap(err, "retrieving stored block"))
}
cblock := &walletrpc.CompactBlock{}
err = proto.Unmarshal(storedBlock, cblock)
if err != nil {
t.Fatal(err)
}
if int(cblock.Height) != lastBlockTest.BlockHeight {
t.Error("incorrect retrieval")
}
}
// Block ranges
{
blockOut := make(chan []byte)
errOut := make(chan error)
count := 0
go GetBlockRange(ctx, db, blockOut, errOut, 289460, 289465)
recvLoop0:
for {
select {
case <-blockOut:
count++
case err := <-errOut:
if err != nil {
t.Error(errors.Wrap(err, "in full blockrange"))
}
break recvLoop0
}
}
if count != 6 {
t.Error("failed to retrieve full range")
}
// Test timeout
timeout, _ := context.WithTimeout(ctx, 0*time.Second)
go GetBlockRange(timeout, db, blockOut, errOut, 289460, 289465)
recvLoop1:
for {
select {
case err := <-errOut:
if err != context.DeadlineExceeded {
t.Errorf("got the wrong error: %v", err)
}
break recvLoop1
}
}
// Test a smaller range
count = 0
go GetBlockRange(ctx, db, blockOut, errOut, 289462, 289465)
recvLoop2:
for {
select {
case <-blockOut:
count++
case err := <-errOut:
if err != nil {
t.Error(errors.Wrap(err, "in short blockrange"))
}
break recvLoop2
}
}
if count != 4 {
t.Errorf("failed to retrieve the shorter range")
}
// Test a nonsense range
count = 0
go GetBlockRange(ctx, db, blockOut, errOut, 1, 2)
recvLoop3:
for {
select {
case <-blockOut:
count++
case err := <-errOut:
if err != nil {
t.Error(errors.Wrap(err, "in invalid blockrange"))
}
break recvLoop3
}
}
if count > 0 {
t.Errorf("got some blocks that shouldn't be there")
}
}
// Transaction storage
{
blockData, _ := hex.DecodeString(compactTests[0].Full)
block := parser.NewBlock()
_, _ = block.ParseFromSlice(blockData)
tx := block.Transactions()[0]
blockHash := hex.EncodeToString(block.GetEncodableHash())
txHash := hex.EncodeToString(tx.GetEncodableHash())
err = StoreTransaction(
db,
block.GetHeight(),
blockHash,
0,
txHash,
tx.Bytes(),
)
if err != nil {
t.Error(err)
}
var storedBytes []byte
getTx := "SELECT tx_bytes FROM transactions WHERE tx_hash = ?"
err = db.QueryRow(getTx, txHash).Scan(&storedBytes)
if err != nil {
t.Error(errors.Wrap(err, fmt.Sprintf("error getting a full transaction")))
}
if len(storedBytes) != len(tx.Bytes()) {
t.Errorf("Wrong tx size, want %d got %d", len(tx.Bytes()), storedBytes)
}
}
}