package database

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"io/ioutil"
	"os"
	"reflect"
	"sort"
	"testing"

	acc "github.com/vapor/account"
	"github.com/vapor/asset"
	"github.com/vapor/blockchain/pseudohsm"
	"github.com/vapor/blockchain/query"
	"github.com/vapor/crypto/ed25519/chainkd"
	dbm "github.com/vapor/database/leveldb"
	"github.com/vapor/protocol/bc"
	"github.com/vapor/testutil"
	"github.com/vapor/wallet"
)

func TestAccountIndexKey(t *testing.T) {
	dirPath, err := ioutil.TempDir(".", "TestAccount")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dirPath)

	hsm, err := pseudohsm.New(dirPath)
	if err != nil {
		t.Fatal(err)
	}

	xpub1, _, err := hsm.XCreate("TestAccountIndex1", "password", "en")
	if err != nil {
		t.Fatal(err)
	}

	xpub2, _, err := hsm.XCreate("TestAccountIndex2", "password", "en")
	if err != nil {
		t.Fatal(err)
	}

	xpubs1 := []chainkd.XPub{xpub1.XPub, xpub2.XPub}
	xpubs2 := []chainkd.XPub{xpub2.XPub, xpub1.XPub}
	if !reflect.DeepEqual(accountIndexKey(xpubs1), accountIndexKey(xpubs2)) {
		t.Fatal("accountIndexKey test err")
	}

	if reflect.DeepEqual(xpubs1, xpubs2) {
		t.Fatal("accountIndexKey test err")
	}
}

func TestDeleteContractUTXO(t *testing.T) {
	cases := []struct {
		utxos      []*acc.UTXO
		deleteUTXO *acc.UTXO
		want       []*acc.UTXO
	}{
		{
			utxos:      []*acc.UTXO{},
			deleteUTXO: &acc.UTXO{},
			want:       []*acc.UTXO{},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x3e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
			},
			deleteUTXO: &acc.UTXO{
				OutputID: bc.NewHash([32]byte{0x3e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			},
			want: []*acc.UTXO{},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x3e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x2e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x3f, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x5e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x6e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x7e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
			},
			deleteUTXO: &acc.UTXO{},
			want: []*acc.UTXO{
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x3e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x2e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x3f, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x5e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x6e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x7e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
			},
		},
		{
			utxos: []*acc.UTXO{},
			deleteUTXO: &acc.UTXO{
				OutputID: bc.NewHash([32]byte{0x3e, 0x94, 0x5d, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			},
			want: []*acc.UTXO{},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x0e, 0x04, 0x50, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x00, 0x01, 0x02, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x01, 0x01, 0x02, 0x39, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
			},
			deleteUTXO: &acc.UTXO{
				OutputID: bc.NewHash([32]byte{0x01, 0x01, 0x02, 0x39, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			},
			want: []*acc.UTXO{
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x0e, 0x04, 0x50, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x00, 0x01, 0x02, 0x35, 0x70, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
				&acc.UTXO{
					OutputID: bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
			},
		},
	}

	for _, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		accountStore := NewAccountStore(testDB)
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		// store mock utxos
		for _, utxo := range c.utxos {
			if err := ws.SetContractUTXO(utxo.OutputID, utxo); err != nil {
				t.Fatal(err)
			}
		}

		// delete utxo
		ws.DeleteContractUTXO(c.deleteUTXO.OutputID)
		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// get utxo by outputID
		for _, utxo := range c.want {
			if _, err := accountStore.GetUTXO(utxo.OutputID); err != nil {
				t.Fatal(err)
			}
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestDeleteRecoveryStatus(t *testing.T) {
	cases := []struct {
		state *wallet.RecoveryState
	}{
		{
			state: &wallet.RecoveryState{},
		},
		{
			state: &wallet.RecoveryState{
				XPubs: []chainkd.XPub{
					chainkd.XPub([64]byte{0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
			},
		},
		{
			state: &wallet.RecoveryState{
				XPubs: []chainkd.XPub{
					chainkd.XPub([64]byte{0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x01, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x02, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x03, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x04, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x05, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x06, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x07, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x08, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x0a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					chainkd.XPub([64]byte{0x0b, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c, 0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		if err := ws.SetRecoveryStatus(c.state); err != nil {
			t.Fatal(err)
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotState, err := ws.GetRecoveryStatus()
		if err != nil {
			t.Fatal(err)
		}

		if !testutil.DeepEqual(gotState, c.state) {
			t.Errorf("case %v: got recovery status, got: %v, want: %v.", i, gotState, c.state)
		}

		ws = walletStore.InitBatch()
		ws.DeleteRecoveryStatus()
		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotState, err = ws.GetRecoveryStatus()
		if err == nil {
			t.Errorf("case %v: got state should fail.", i)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestGetWalletInfo(t *testing.T) {
	cases := []struct {
		state *wallet.StatusInfo
	}{
		{
			state: &wallet.StatusInfo{},
		},
		{
			state: &wallet.StatusInfo{
				Version:    uint(0),
				WorkHeight: uint64(9),
				WorkHash:   bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				BestHash:   bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				BestHeight: uint64(0),
			},
		},
		{
			state: &wallet.StatusInfo{
				Version:    uint(9),
				WorkHeight: uint64(9999999),
				WorkHash:   bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				BestHash:   bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				BestHeight: uint64(100000),
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		if err := ws.SetWalletInfo(c.state); err != nil {
			t.Fatal(err)
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotState, err := ws.GetWalletInfo()
		if err != nil {
			t.Fatal(err)
		}

		if !testutil.DeepEqual(gotState, c.state) {
			t.Errorf("case %v: got wallet info, got: %v, want: %v.", i, gotState, c.state)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestDeleteUnconfirmedTransaction(t *testing.T) {
	cases := []struct {
		tx *query.AnnotatedTx
	}{
		{
			tx: &query.AnnotatedTx{},
		},
		{
			tx: &query.AnnotatedTx{
				ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				Timestamp:   uint64(100),
				BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				BlockHeight: uint64(100),
				Position:    uint32(100),
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		if err := ws.SetUnconfirmedTransaction(c.tx.ID.String(), c.tx); err != nil {
			t.Fatal(err)
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotTx, err := ws.GetUnconfirmedTransaction(c.tx.ID.String())
		if err != nil {
			t.Fatal(err)
		}

		if !testutil.DeepEqual(gotTx, c.tx) {
			t.Errorf("case %v: got unconfirmed transaction, got: %v, want: %v.", i, gotTx, c.tx)
		}

		ws = walletStore.InitBatch()
		ws.DeleteUnconfirmedTransaction(c.tx.ID.String())
		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotTx, err = ws.GetUnconfirmedTransaction(c.tx.ID.String())
		if err == nil {
			t.Errorf("case %v: got unconfirmed transaction should fail.", i)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestListUnconfirmedTransactions(t *testing.T) {
	cases := []struct {
		txs []*query.AnnotatedTx
	}{
		{
			txs: []*query.AnnotatedTx{},
		},
		{
			txs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
			},
		},
		{
			txs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x05, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x05, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x06, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x06, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x07, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x07, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x08, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x08, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(100),
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		for _, tx := range c.txs {
			if err := ws.SetUnconfirmedTransaction(tx.ID.String(), tx); err != nil {
				t.Fatal(err)
			}
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotTxs, err := ws.ListUnconfirmedTransactions()
		if err != nil {
			t.Fatal(err)
		}

		sort.Sort(SortUnconfirmedTxs(gotTxs))
		sort.Sort(SortUnconfirmedTxs(c.txs))

		if !testutil.DeepEqual(gotTxs, c.txs) {
			t.Errorf("case %v: list unconfirmed transactions, got: %v, want: %v.", i, gotTxs, c.txs)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

type SortUnconfirmedTxs []*query.AnnotatedTx

func (s SortUnconfirmedTxs) Len() int { return len(s) }
func (s SortUnconfirmedTxs) Less(i, j int) bool {
	return bytes.Compare(s[i].ID.Bytes(), s[j].ID.Bytes()) < 0
}
func (s SortUnconfirmedTxs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func TestGetGlobalTransactionIndex(t *testing.T) {
	cases := []struct {
		globalTxID string
		blockHash  bc.Hash
		position   uint64
	}{
		{
			globalTxID: "",
			blockHash:  bc.NewHash([32]byte{}),
			position:   uint64(0),
		},
		{
			globalTxID: "8838474e18e945e2f648745a362ac6988bad172b0eef5c593038a2fc8b46261e",
			blockHash:  bc.NewHash([32]byte{0x00, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			position:   uint64(0),
		},
		{
			globalTxID: "d8de517917a591daa447d6be28ffb2fac866703e4feb65e86221be9a22d3033a",
			blockHash:  bc.NewHash([32]byte{0x00, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			position:   uint64(99),
		},
		{
			globalTxID: "f4c64e9f72623c26b06e17f909aec7c03c927fcf681781489257097e537b8d5a",
			blockHash:  bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			position:   uint64(99),
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		ws.SetGlobalTransactionIndex(c.globalTxID, &c.blockHash, c.position)

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotIndex := ws.GetGlobalTransactionIndex(c.globalTxID)
		wantIndex := CalcGlobalTxIndex(&c.blockHash, c.position)

		if !testutil.DeepEqual(gotIndex, wantIndex) {
			t.Errorf("case %v: got global transaction index, got: %v, want: %v.", i, gotIndex, wantIndex)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestGetAsset(t *testing.T) {
	cases := []struct {
		asset *asset.Asset
	}{
		{
			asset: &asset.Asset{
				AssetID:       bc.NewAssetID([32]byte{}),
				DefinitionMap: map[string]interface{}{},
			},
		},
		{
			asset: &asset.Asset{
				AssetID:       bc.NewAssetID([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				DefinitionMap: map[string]interface{}{},
			},
		},
		{
			asset: &asset.Asset{
				AssetID: bc.NewAssetID([32]byte{}),
				DefinitionMap: map[string]interface{}{
					"Name": "assetname",
				},
			},
		},
		{
			asset: &asset.Asset{
				AssetID: bc.NewAssetID([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				DefinitionMap: map[string]interface{}{
					"Name": "assetname",
				},
			},
		},
		{
			asset: &asset.Asset{
				AssetID: bc.NewAssetID([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
				DefinitionMap: map[string]interface{}{
					"Name":   "assetname",
					"Amount": "1000000",
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		definitionByte, err := json.Marshal(c.asset.DefinitionMap)
		if err != nil {
			t.Fatal(err)
		}

		ws.SetAssetDefinition(&c.asset.AssetID, definitionByte)
		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotAsset, err := ws.GetAsset(&c.asset.AssetID)
		if err != nil {
			t.Fatal(err)
		}

		if !testutil.DeepEqual(gotAsset.DefinitionMap, c.asset.DefinitionMap) {
			t.Errorf("case %v: got asset, got: %v, want: %v.", i, gotAsset.DefinitionMap, c.asset.DefinitionMap)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestDeleteTransactions(t *testing.T) {
	cases := []struct {
		height uint64
		txs    []*query.AnnotatedTx
	}{
		{
			height: uint64(0),
			txs:    []*query.AnnotatedTx{},
		},
		{
			height: uint64(0),
			txs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(0),
					Position:    uint32(2333),
				},
			},
		},
		{
			height: uint64(1000000),
			txs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(0),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(1),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(2),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(3),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x05, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(4),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x06, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(5),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x07, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(6),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x08, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(7),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x09, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(8),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x0a, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(9),
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		// store txs by given height
		for _, tx := range c.txs {
			if err := ws.SetTransaction(c.height, tx); err != nil {
				t.Fatal(err)
			}
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// get tx by txID
		for j := 0; j < len(c.txs); j++ {
			gotTx, err := ws.GetTransaction(c.txs[j].ID.String())
			if err != nil {
				t.Fatal(err)
			}

			if !testutil.DeepEqual(gotTx, c.txs[j]) {
				t.Errorf("case %v: got transaction, got: %v, want: %v.", i, gotTx, c.txs[j])
			}
		}

		// delete all txs by given height
		ws = walletStore.InitBatch()
		ws.DeleteTransactions(c.height)
		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// get tx by txID, it should return err
		for _, tx := range c.txs {
			_, err := ws.GetTransaction(tx.ID.String())
			if err == nil {
				t.Errorf("case: %v: it should return some err.", i)
			}
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestDeleteWalletTransactions(t *testing.T) {
	cases := []struct {
		height uint64
		txs    []*query.AnnotatedTx
	}{
		{
			height: uint64(0),
			txs:    []*query.AnnotatedTx{},
		},
		{
			height: uint64(0),
			txs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(0),
					Position:    uint32(2333),
				},
			},
		},
		{
			height: uint64(1000000),
			txs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(0),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(1),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(2),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(3),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x05, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(4),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x06, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(5),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x07, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(6),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x08, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(7),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x09, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(8),
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x0a, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(9988000),
					BlockHeight: uint64(1000000),
					Position:    uint32(9),
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		// store txs by given height
		for _, tx := range c.txs {
			if err := ws.SetTransaction(c.height, tx); err != nil {
				t.Fatal(err)
			}
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// delete all txs
		ws = walletStore.InitBatch()
		ws.DeleteWalletTransactions()
		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// get tx by txID, it should return err
		for _, tx := range c.txs {
			_, err := ws.GetTransaction(tx.ID.String())
			if err == nil {
				t.Errorf("case: %v: it should return some err.", i)
			}
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestDeleteWalletUTXOs(t *testing.T) {
	cases := []struct {
		utxos []*acc.UTXO
	}{
		{
			utxos: []*acc.UTXO{},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address1",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address2",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address3",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address4",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address5",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address6",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address7",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address8",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address9",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		// store utxos
		for _, utxo := range c.utxos {
			if err := ws.SetContractUTXO(utxo.OutputID, utxo); err != nil {
				t.Fatal(err)
			}
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// delete all utxos
		ws = walletStore.InitBatch()
		ws.DeleteWalletUTXOs()
		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// get utxo by outputID, it should return err
		accountStore := NewAccountStore(testDB)
		for _, utxo := range c.utxos {
			_, err := accountStore.GetUTXO(utxo.OutputID)
			if err == nil {
				t.Errorf("case: %v: it should return some err.", i)
			}
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestGetStandardUTXO(t *testing.T) {
	cases := []struct {
		utxos []*acc.UTXO
	}{
		{
			utxos: []*acc.UTXO{},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
		{
			utxos: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address1",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address2",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address3",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address4",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address5",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address6",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address7",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address8",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address9",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		accountStore := NewAccountStore(testDB)
		as := accountStore.InitBatch()
		// store utxos
		for _, utxo := range c.utxos {
			if err := as.SetStandardUTXO(utxo.OutputID, utxo); err != nil {
				t.Fatal(err)
			}
		}

		if err := as.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// get utxo by outputID
		walletStore := NewWalletStore(testDB)
		for _, utxo := range c.utxos {
			gotUTXO, err := walletStore.GetStandardUTXO(utxo.OutputID)
			if err != nil {
				t.Fatal(err)
			}

			if !testutil.DeepEqual(gotUTXO, utxo) {
				t.Errorf("case %v: got standard utxo, got: %v, want: %v.", i, gotUTXO, utxo)
			}
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestListAccountUTXOs(t *testing.T) {
	cases := []struct {
		standardUTXOs   []*acc.UTXO
		contractUTXOs   []*acc.UTXO
		id              string
		isSmartContract bool
		want            []*acc.UTXO
	}{
		{
			standardUTXOs:   []*acc.UTXO{},
			contractUTXOs:   []*acc.UTXO{},
			id:              "",
			isSmartContract: false,
			want:            []*acc.UTXO{},
		},
		{
			standardUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			contractUTXOs:   []*acc.UTXO{},
			id:              "01f3",
			isSmartContract: false,
			want:            []*acc.UTXO{},
		},
		{
			standardUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			contractUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			id:              "01f3",
			isSmartContract: true,
			want:            []*acc.UTXO{},
		},
		{
			standardUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x02, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			contractUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			id:              "",
			isSmartContract: false,
			want: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x02, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
		{
			standardUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x02, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			contractUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			id:              "02",
			isSmartContract: false,
			want: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x02, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
		{
			standardUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			contractUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			id:              "",
			isSmartContract: true,
			want: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
		{
			standardUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x01, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			contractUTXOs: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x04, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
			id:              "03",
			isSmartContract: true,
			want: []*acc.UTXO{
				&acc.UTXO{
					OutputID:  bc.NewHash([32]byte{0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Address:   "address0",
					Amount:    uint64(0),
					Change:    true,
					AccountID: "account",
					SourcePos: uint64(0),
				},
			},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		accountStore := NewAccountStore(testDB)
		as := accountStore.InitBatch()
		// store standard utxos
		for _, utxo := range c.standardUTXOs {
			if err := as.SetStandardUTXO(utxo.OutputID, utxo); err != nil {
				t.Fatal(err)
			}
		}

		if err := as.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// store contract utxos
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		for _, utxo := range c.contractUTXOs {
			if err := ws.SetContractUTXO(utxo.OutputID, utxo); err != nil {
				t.Fatal(err)
			}
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		gotUTXOs, err := ws.ListAccountUTXOs(c.id, c.isSmartContract)
		if err != nil {
			t.Fatal(err)
		}

		if !testutil.DeepEqual(gotUTXOs, c.want) {
			t.Errorf("case %v: list account utxos, got: %v, want: %v.", i, gotUTXOs, c.want)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

func TestListTransactions(t *testing.T) {
	cases := []struct {
		unconfirmedTxs []*query.AnnotatedTx
		confirmedTxs   []*query.AnnotatedTx
		height         uint64
		accountID      string
		startTxID      string
		count          uint
		unconfirmed    bool
		want           []*query.AnnotatedTx
	}{
		{
			unconfirmedTxs: []*query.AnnotatedTx{},
			confirmedTxs:   []*query.AnnotatedTx{},
			height:         uint64(0),
			accountID:      "",
			startTxID:      "",
			count:          uint(0),
			unconfirmed:    false,
			want:           []*query.AnnotatedTx{},
		},
		{
			unconfirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(1),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			confirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(102),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(103),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			height:      uint64(100),
			accountID:   "",
			startTxID:   "",
			count:       uint(0),
			unconfirmed: false,
			want:        []*query.AnnotatedTx{},
		},
		{
			unconfirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(120),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			confirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(130),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(140),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			height:      uint64(100),
			accountID:   "",
			startTxID:   "",
			count:       uint(2),
			unconfirmed: false,
			want: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(130),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(140),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
		},
		{
			unconfirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(120),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			confirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(130),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(140),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			height:      uint64(100),
			accountID:   "",
			startTxID:   "",
			count:       uint(2),
			unconfirmed: true,
			want: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(120),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
		},
		{
			unconfirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(120),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account2",
						},
					},
				},
			},
			confirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(130),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(140),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			height:      uint64(100),
			accountID:   "account1",
			startTxID:   "",
			count:       uint(2),
			unconfirmed: true,
			want: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
		},
		{
			unconfirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(120),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			confirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(130),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(140),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			height:      uint64(100),
			accountID:   "",
			startTxID:   hex.EncodeToString([]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			count:       uint(2),
			unconfirmed: true,
			want: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
		},
		{
			unconfirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(101),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x02, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(120),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			confirmedTxs: []*query.AnnotatedTx{
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x03, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(130),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
				&query.AnnotatedTx{
					ID:          bc.NewHash([32]byte{0x04, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					Timestamp:   uint64(100),
					BlockID:     bc.NewHash([32]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
					BlockHeight: uint64(100),
					Position:    uint32(140),
					Inputs: []*query.AnnotatedInput{
						&query.AnnotatedInput{
							AccountID: "account1",
						},
					},
				},
			},
			height:      uint64(100),
			accountID:   "",
			startTxID:   hex.EncodeToString([]byte{0x01, 0x01, 0x51, 0x31, 0x71, 0x30, 0xd4, 0x3b, 0x3d, 0xe3, 0xdd, 0x80, 0x67, 0x29, 0x9a, 0x5e, 0x09, 0xf9, 0xfb, 0x2b, 0xad, 0x5f, 0x92, 0xc8, 0x69, 0xd1, 0x42, 0x39, 0x74, 0x9a, 0xd1, 0x1c}),
			count:       uint(2),
			unconfirmed: true,
			want:        []*query.AnnotatedTx{},
		},
	}

	for i, c := range cases {
		testDB := dbm.NewDB("testdb", "leveldb", "temp")
		walletStore := NewWalletStore(testDB)
		ws := walletStore.InitBatch()
		// store unconfirmed txs
		for _, tx := range c.unconfirmedTxs {
			if err := ws.SetUnconfirmedTransaction(tx.ID.String(), tx); err != nil {
				t.Fatal(err)
			}
		}

		// store confirmed txs
		for _, tx := range c.confirmedTxs {
			if err := ws.SetTransaction(c.height, tx); err != nil {
				t.Fatal(err)
			}
		}

		if err := ws.CommitBatch(); err != nil {
			t.Fatal(err)
		}

		// get txs by given accountID, startID, count, unconfirmed
		gotTxs, err := ws.ListTransactions(c.accountID, c.startTxID, c.count, c.unconfirmed)
		if err != nil {
			t.Fatal(err)
		}

		sort.Sort(SortAnnotatedTxs(gotTxs))
		sort.Sort(SortAnnotatedTxs(c.want))

		if !testutil.DeepEqual(gotTxs, c.want) {
			t.Errorf("case %v: list transactions, got: %v, want: %v.", i, gotTxs, c.want)
		}

		testDB.Close()
		os.RemoveAll("temp")
	}
}

type SortAnnotatedTxs []*query.AnnotatedTx

func (s SortAnnotatedTxs) Len() int { return len(s) }
func (s SortAnnotatedTxs) Less(i, j int) bool {
	return bytes.Compare(s[i].ID.Bytes(), s[j].ID.Bytes()) < 0
}
func (s SortAnnotatedTxs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
