func (e *Engine) addPartialTradeOrder(tx *types.Tx) error {
for i, output := range tx.Outputs {
- if !segwit.IsP2WMCScript(output.ControlProgram()) {
+ if !segwit.IsP2WMCScript(output.ControlProgram()) || output.AssetAmount().Amount == 0 {
continue
}
for i, receivedAmount := range receivedAmounts {
oppositeShouldPayAmount := shouldPayAmounts[calcOppositeIndex(len(orders), i)]
if oppositeShouldPayAmount.Amount > receivedAmount.Amount {
- assetId := oppositeShouldPayAmount.AssetId
+ assetID := oppositeShouldPayAmount.AssetId
amount := oppositeShouldPayAmount.Amount - receivedAmount.Amount
- priceDiffs = append(priceDiffs, &bc.AssetAmount{AssetId: assetId, Amount: amount})
+ priceDiffs = append(priceDiffs, &bc.AssetAmount{AssetId: assetID, Amount: amount})
}
}
return receivedAmounts, priceDiffs
errRewardProgramIsWrong = errors.New("the reward program is not correct")
)
-// MovCore represent the core logic of the match module, which include generate match transactions before packing the block,
+// Core represent the core logic of the match module, which include generate match transactions before packing the block,
// verify the match transaction in block is correct, and update the order table according to the transaction.
-type MovCore struct {
+type Core struct {
movStore database.MovStore
startBlockHeight uint64
}
-// NewMovCore return a instance of MovCore by path of mov db
-func NewMovCore(dbBackend, dbDir string, startBlockHeight uint64) *MovCore {
+// NewCore return a instance of Core by path of mov db
+func NewCore(dbBackend, dbDir string, startBlockHeight uint64) *Core {
movDB := dbm.NewDB("mov", dbBackend, dbDir)
- return &MovCore{movStore: database.NewLevelDBMovStore(movDB), startBlockHeight: startBlockHeight}
+ return &Core{movStore: database.NewLevelDBMovStore(movDB), startBlockHeight: startBlockHeight}
}
-// NewMovCoreWithDB return a instance of MovCore by movStore
-func NewMovCoreWithDB(store *database.LevelDBMovStore, startBlockHeight uint64) *MovCore {
- return &MovCore{movStore: store, startBlockHeight: startBlockHeight}
+// NewCoreWithDB return a instance of Core by movStore
+func NewCoreWithDB(store *database.LevelDBMovStore, startBlockHeight uint64) *Core {
+ return &Core{movStore: store, startBlockHeight: startBlockHeight}
}
// ApplyBlock parse pending order and cancel from the the transactions of block
// and add pending order to the dex db, remove cancel order from dex db.
-func (m *MovCore) ApplyBlock(block *types.Block) error {
+func (m *Core) ApplyBlock(block *types.Block) error {
if block.Height < m.startBlockHeight {
return nil
}
if block.Height == m.startBlockHeight {
blockHash := block.Hash()
- if err := m.movStore.InitDBState(block.Height, &blockHash); err != nil {
- return err
- }
-
- // the next block can send orders
- return nil
+ return m.movStore.InitDBState(block.Height, &blockHash)
}
if err := m.validateMatchedTxSequence(block.Transactions); err != nil {
}
// BeforeProposalBlock return all transactions than can be matched, and the number of transactions cannot exceed the given capacity.
-func (m *MovCore) BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error) {
+func (m *Core) BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error) {
if blockHeight <= m.startBlockHeight {
return nil, nil
}
}
// ChainStatus return the current block height and block hash in dex core
-func (m *MovCore) ChainStatus() (uint64, *bc.Hash, error) {
+func (m *Core) ChainStatus() (uint64, *bc.Hash, error) {
state, err := m.movStore.GetMovDatabaseState()
if err != nil {
return 0, nil, err
// DetachBlock parse pending order and cancel from the the transactions of block
// and add cancel order to the dex db, remove pending order from dex db.
-func (m *MovCore) DetachBlock(block *types.Block) error {
+func (m *Core) DetachBlock(block *types.Block) error {
if block.Height < m.startBlockHeight {
return nil
}
}
// IsDust block the transaction that are not generated by the match engine
-func (m *MovCore) IsDust(tx *types.Tx) bool {
+func (m *Core) IsDust(tx *types.Tx) bool {
for _, input := range tx.Inputs {
if segwit.IsP2WMCScript(input.ControlProgram()) && !contract.IsCancelClauseSelector(input) {
return true
}
// Name return the name of current module
-func (m *MovCore) Name() string {
+func (m *Core) Name() string {
return "MOV"
}
// StartHeight return the start block height of current module
-func (m *MovCore) StartHeight() uint64 {
+func (m *Core) StartHeight() uint64 {
return m.startBlockHeight
}
// ValidateBlock no need to verify the block header, because the first module has been verified.
// just need to verify the transactions in the block.
-func (m *MovCore) ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error {
+func (m *Core) ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error {
for i, tx := range block.Transactions {
if err := m.ValidateTx(tx, verifyResults[i], block.Height); err != nil {
return err
}
// ValidateTx validate one transaction.
-func (m *MovCore) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error {
+func (m *Core) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error {
+ if blockHeight <= m.startBlockHeight {
+ return nil
+ }
+
+ if verifyResult.StatusFail {
+ return errStatusFailMustFalse
+ }
+
if common.IsMatchedTx(tx) {
if err := validateMatchedTx(tx, verifyResult, blockHeight); err != nil {
return err
if !segwit.IsP2WMCScript(output.ControlProgram()) {
continue
}
- if verifyResult.StatusFail {
- return errStatusFailMustFalse
- }
if err := validateMagneticContractArgs(output.AssetAmount(), output.ControlProgram()); err != nil {
return err
if assetFeeMap[*assetAmount.AssetId].amount <= 0 {
delete(assetFeeMap, *assetAmount.AssetId)
}
- } else {
+ } else if assetFeeMap[*assetAmount.AssetId].rewardProgram == nil {
assetFeeMap[*assetAmount.AssetId].rewardProgram = output.ControlProgram()
+ } else {
+ return nil, errors.Wrap(errRewardProgramIsWrong, "double reward program")
}
}
return assetFeeMap, nil
}
func validateCancelOrderTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error {
- if verifyResult.StatusFail {
- return errStatusFailMustFalse
- }
-
for _, input := range tx.Inputs {
if !segwit.IsP2WMCScript(input.ControlProgram()) {
return errInputProgramMustP2WMCScript
}
func validateMatchedTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error {
- if verifyResult.StatusFail {
- return errStatusFailMustFalse
- }
-
fromAssetIDMap := make(map[string]bool)
toAssetIDMap := make(map[string]bool)
for i, input := range tx.Inputs {
return feeStrategy.Validate(receivedAmount, feeAmounts)
}
-func (m *MovCore) validateMatchedTxSequence(txs []*types.Tx) error {
+func (m *Core) validateMatchedTxSequence(txs []*types.Tx) error {
orderBook := match.NewOrderBook(m.movStore, nil, nil)
for _, tx := range txs {
if common.IsMatchedTx(tx) {
}
func buildOrderBook(store database.MovStore, txs []*types.Tx) (*match.OrderBook, error) {
- var nonMatchedTxs []*types.Tx
- for _, tx := range txs {
- if !common.IsMatchedTx(tx) {
- nonMatchedTxs = append(nonMatchedTxs, tx)
- }
- }
-
var arrivalAddOrders, arrivalDelOrders []*common.Order
- for _, tx := range nonMatchedTxs {
+ for _, tx := range txs {
addOrders, err := getAddOrdersFromTx(tx)
if err != nil {
return nil, err
continue
}
+ if output.AssetAmount().Amount == 0 {
+ continue
+ }
+
order, err := common.NewOrderFromOutput(tx, i)
if err != nil {
return nil, err
t.Fatal(err)
}
- movCore := &MovCore{movStore: store}
+ movCore := &Core{movStore: store}
if err := c.blockFunc(movCore, c.block); err != c.wantError {
t.Errorf("#%d(%s):apply block want error(%v), got error(%v)", i, c.desc, c.wantError, err)
}
}
for i, c := range cases {
- movCore := &MovCore{}
+ movCore := &Core{}
+ c.block.Height = 3456786543
if err := movCore.ValidateBlock(c.block, c.verifyResults); err != c.wantError {
t.Errorf("#%d(%s):validate block want error(%v), got error(%v)", i, c.desc, c.wantError, err)
}
tx: mock.MatchedTxs[1].TxData,
},
{
- desc: "fee refund in tx",
- maxFeeRate: 0.05,
+ desc: "fee refund in tx",
+ maxFeeRate: 0.05,
wantMatchedTxFee: map[bc.AssetID]*matchedTxFee{
mock.ETH: {amount: 25, rewardProgram: mock.RewardProgram},
mock.BTC: {amount: 1, rewardProgram: mock.RewardProgram},
},
- tx: mock.MatchedTxs[2].TxData,
+ tx: mock.MatchedTxs[2].TxData,
},
{
- desc: "no price diff",
- maxFeeRate: 0.05,
+ desc: "no price diff",
+ maxFeeRate: 0.05,
wantMatchedTxFee: map[bc.AssetID]*matchedTxFee{
mock.ETH: {amount: 1, rewardProgram: mock.RewardProgram},
mock.BTC: {amount: 1, rewardProgram: mock.RewardProgram},
},
- tx: mock.MatchedTxs[0].TxData,
+ tx: mock.MatchedTxs[0].TxData,
},
}
t.Fatal(err)
}
- movCore := &MovCore{movStore: store}
+ movCore := &Core{movStore: store}
gotMatchedTxs, err := movCore.BeforeProposalBlock(nil, 2, c.gasLeft, func() bool { return false })
if err != nil {
t.Fatal(err)
t.Fatal(err)
}
- movCore := &MovCore{movStore: store}
+ movCore := &Core{movStore: store}
if err := movCore.validateMatchedTxSequence(c.transactions); err != c.wantError {
t.Errorf("#%d(%s):wanet error(%v), got error(%v)", i, c.desc, c.wantError, err)
}
}
}
-type testFun func(movCore *MovCore, block *types.Block) error
+type testFun func(movCore *Core, block *types.Block) error
-func applyBlock(movCore *MovCore, block *types.Block) error {
+func applyBlock(movCore *Core, block *types.Block) error {
return movCore.ApplyBlock(block)
}
-func detachBlock(movCore *MovCore, block *types.Block) error {
+func detachBlock(movCore *Core, block *types.Block) error {
return movCore.DetachBlock(block)
}
"github.com/bytom/vapor/errors"
)
+// AddDataWitness append data to the witness array
func (si *SigningInstruction) AddDataWitness(data chainjson.HexBytes) {
dw := DataWitness(data)
si.WitnessComponents = append(si.WitnessComponents, &dw)
config = cfg.DefaultConfig()
)
+// RootCmd is the command for run node
var RootCmd = &cobra.Command{
Use: "vapord",
Short: "Multiple asset management.",
"encoding/hex"
)
+// FromHex convert hex byte string to []byte
func FromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" {
return nil
}
+// Bytes2Hex convert byte array to string
func Bytes2Hex(d []byte) string {
return hex.EncodeToString(d)
}
+// Hex2Bytes convert hex string to byte array
func Hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
+// Unit64ToBytes convert uint64 to bytes
func Unit64ToBytes(n uint64) []byte {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, n)
return buf
}
+// BytesToUnit64 convert bytes to uint64
func BytesToUnit64(b []byte) uint64 {
return binary.LittleEndian.Uint64(b)
}
"encoding/json"
)
+// IsOpenFederationIssueAsset check if the asset definition satisfy ofmf asset
func IsOpenFederationIssueAsset(rawDefinitionByte []byte) bool {
var defMap map[string]interface{}
if err := json.Unmarshal(rawDefinitionByte, &defMap); err != nil {
+++ /dev/null
-package common
-
-// timeSorter implements sort.Interface to allow a slice of timestamps to
-// be sorted.
-type TimeSorter []uint64
-
-// Len returns the number of timestamps in the slice. It is part of the
-// sort.Interface implementation.
-func (s TimeSorter) Len() int {
- return len(s)
-}
-
-// Swap swaps the timestamps at the passed indices. It is part of the
-// sort.Interface implementation.
-func (s TimeSorter) Swap(i, j int) {
- s[i], s[j] = s[j], s[i]
-}
-
-// Less returns whether the timstamp with index i should sort before the
-// timestamp with index j. It is part of the sort.Interface implementation.
-func (s TimeSorter) Less(i, j int) bool {
- return s[i] < s[j]
-}
return &Params{Bech32HRPSegwit: bech32HRPSegwit}
}
+// InitActiveNetParams load the config by chain ID
func InitActiveNetParams(chainID string) error {
var exist bool
if ActiveNetParams, exist = NetParams[chainID]; !exist {
return append(AccountIndexPrefix, hash[:]...)
}
-func Bip44ContractIndexKey(accountID string, change bool) []byte {
+func bip44ContractIndexKey(accountID string, change bool) []byte {
key := append(ContractIndexPrefix, []byte(accountID)...)
if change {
return append(key, 0x01)
// CommitBatch commit batch
func (store *AccountStore) CommitBatch() error {
if store.batch == nil {
- return errors.New("AccountStore commit fail, store batch is nil.")
+ return errors.New("accountStore commit fail, store batch is nil")
}
store.batch.Write()
store.batch = nil
}
// delete bip44 contract index
- batch.Delete(Bip44ContractIndexKey(account.ID, false))
- batch.Delete(Bip44ContractIndexKey(account.ID, true))
+ batch.Delete(bip44ContractIndexKey(account.ID, false))
+ batch.Delete(bip44ContractIndexKey(account.ID, true))
// delete contract index
batch.Delete(contractIndexKey(account.ID))
// GetBip44ContractIndex get bip44 contract index
func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
index := uint64(0)
- if rawIndexBytes := store.db.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
+ if rawIndexBytes := store.db.Get(bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
index = common.BytesToUnit64(rawIndexBytes)
}
return index
// SetBip44ContractIndex set contract index
func (store *AccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
if store.batch == nil {
- store.db.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
+ store.db.Set(bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
} else {
- store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
+ store.batch.Set(bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
}
}
package database
import (
- "github.com/golang/protobuf/proto"
dbm "github.com/bytom/vapor/database/leveldb"
"github.com/bytom/vapor/database/storage"
"github.com/bytom/vapor/errors"
"github.com/bytom/vapor/protocol/bc"
"github.com/bytom/vapor/protocol/state"
+ "github.com/golang/protobuf/proto"
)
const utxoPreFix = "UT:"
return nil
}
+// SaveUtxoView is export for intergation test
func SaveUtxoView(batch dbm.Batch, view *state.UtxoViewpoint) error {
return saveUtxoView(batch, view)
}
recoveryKey //recoveryKey key for db store recovery info.
)
+// pre-define variables
var (
walletStore = []byte("WS:")
SUTXOPrefix = append(walletStore, sutxoPrefix, colon)
return append(UnconfirmedTxPrefix, []byte(formatKey)...)
}
+// CalcGlobalTxIndexKey calculate tx hash index key
func CalcGlobalTxIndexKey(txID string) []byte {
return append(GlobalTxIndexPrefix, []byte(txID)...)
}
+// CalcGlobalTxIndex calcuate the block index + position index key
func CalcGlobalTxIndex(blockHash *bc.Hash, position uint64) []byte {
txIdx := make([]byte, 40)
copy(txIdx[:32], blockHash.Bytes())
// CommitBatch commit batch
func (store *WalletStore) CommitBatch() error {
if store.batch == nil {
- return errors.New("WalletStore commit fail, store batch is nil.")
+ return errors.New("walletStore commit fail, store batch is nil")
}
store.batch.Write()
return confirmedUTXOs, nil
}
+// ListTransactions list tx by filter args
func (store *WalletStore) ListTransactions(accountID string, StartTxID string, count uint, unconfirmed bool) ([]*query.AnnotatedTx, error) {
annotatedTxs := []*query.AnnotatedTx{}
var startKey []byte
package math
+// MinUint64 return the min of x and y
func MinUint64(x, y uint64) uint64 {
if x < y {
return x
"errors"
"net"
"net/http"
+ // debug tool
_ "net/http/pprof"
"path/filepath"
"reflect"
accessTokens := accesstoken.NewStore(tokenDB)
dispatcher := event.NewDispatcher()
- movCore := mov.NewMovCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
+ movCore := mov.NewCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
assetFilter := protocol.NewAssetFilter(config.CrossChain.AssetWhitelist)
txPool := protocol.NewTxPool(store, []protocol.DustFilterer{movCore, assetFilter}, dispatcher)
chain, err := protocol.NewChain(store, txPool, []protocol.Protocoler{movCore}, dispatcher)
store := database.NewStore(coreDB)
dispatcher := event.NewDispatcher()
- movCore := mov.NewMovCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
+ movCore := mov.NewCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
txPool := protocol.NewTxPool(store, []protocol.DustFilterer{movCore}, dispatcher)
chain, err := protocol.NewChain(store, txPool, []protocol.Protocoler{movCore}, dispatcher)
if err != nil {
typedInput := genesisBlock.Transactions[0].Inputs[0].TypedInput
if v, ok := typedInput.(*types.CoinbaseInput); ok {
if !reflect.DeepEqual(fedpegScript, v.Arbitrary) {
- return errors.New("config xpubs don't equal genesis block xpubs.")
+ return errors.New("config xpubs don't equal genesis block xpubs")
}
}
return nil
n.api.StartServer(*listenAddr)
}
+// OnStart implements BaseService
func (n *Node) OnStart() error {
if n.miningEnable {
if _, err := n.wallet.AccountMgr.GetMiningAddress(); err != nil {
return nil
}
+// OnStop implements BaseService
func (n *Node) OnStop() {
n.notificationMgr.Shutdown()
n.notificationMgr.WaitForShutdown()
n.eventDispatcher.Stop()
}
+// RunForever listen to the stop signal
func (n *Node) RunForever() {
// Sleep forever and then...
cmn.TrapSignal(func() {
"github.com/bytom/vapor/protocol/bc/types"
)
-type assetFilter struct {
+// AssetFilter is struct for allow open federation asset cross chain
+type AssetFilter struct {
whitelist map[string]struct{}
}
// NewAssetFilter returns a assetFilter according a whitelist,
// which is a strings list cancated via comma
-func NewAssetFilter(whitelist string) *assetFilter {
- af := &assetFilter{whitelist: make(map[string]struct{})}
+func NewAssetFilter(whitelist string) *AssetFilter {
+ af := &AssetFilter{whitelist: make(map[string]struct{})}
af.whitelist[consensus.BTMAssetID.String()] = struct{}{}
for _, assetID := range strings.Split(whitelist, ",") {
af.whitelist[strings.ToLower(assetID)] = struct{}{}
// IsDust implements the DustFilterer interface.
// It filters a transaction as long as there is one asset neither BTM or in the whitelist
// No need to check the output assets types becauese they must have been cover in input assets types
-func (af *assetFilter) IsDust(tx *types.Tx) bool {
+func (af *AssetFilter) IsDust(tx *types.Tx) bool {
for _, input := range tx.Inputs {
if _, ok := input.TypedInput.(*types.CrossChainInput); !ok {
continue
return nil, err
}
+ if len(blockHeader.Get(node.Order)) != 0 {
+ return nil, nil
+ }
+
if err := c.checkDoubleSign(blockHeader, node.XPub.String()); err == errDoubleSignBlock {
log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String()}).Warn("current node has double sign the block")
return nil, nil
return nil, err
}
- if signature := blockHeader.Get(node.Order); len(signature) != 0 {
- return nil, nil
- }
-
signature := xprv.Sign(blockHeader.Hash().Bytes())
blockHeader.Set(node.Order, signature)
return signature, nil
return nil
}
+// WriteTo write block to io.Writer
func (b *Block) WriteTo(w io.Writer) (int64, error) {
ew := errors.NewWriter(w)
if err := b.writeTo(ew, SerBlockFull); err != nil {
"github.com/bytom/vapor/encoding/blockchain"
)
+// BlockWitness save the consensus node sign
type BlockWitness struct {
// Witness is a vector of arguments for validating this block.
Witness [][]byte
return err
}
+// Set save data to index position
func (bw *BlockWitness) Set(index uint64, data []byte) {
if uint64(len(bw.Witness)) <= index {
newWitness := make([][]byte, index+1, index+1)
bw.Witness[index] = data
}
+// Delete remove data from index position
func (bw *BlockWitness) Delete(index uint64) {
if uint64(len(bw.Witness)) > index {
bw.Witness[index] = nil
}
}
+// Get return data from index position
func (bw *BlockWitness) Get(index uint64) []byte {
if uint64(len(bw.Witness)) > index {
return bw.Witness[index]
}
}
+// OutputType implement the txout interface
func (it *CrossChainOutput) OutputType() uint8 { return CrossChainOutputType }
}
}
+// OutputType implement the txout interface
func (it *IntraChainOutput) OutputType() uint8 { return IntraChainOutputType }
}
}
+// OutputType implement the txout interface
func (it *VoteOutput) OutputType() uint8 { return VoteOutputType }
if err != nil {
return err
}
+
if err := consensusResult.ApplyBlock(block); err != nil {
return err
}
maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
)
+// Protocoler is interface for layer 2 consensus protocol
type Protocoler interface {
Name() string
StartHeight() uint64
return *blockHash == hash
}
+// SubProtocols return list of layer 2 consensus protocol
func (c *Chain) SubProtocols() []Protocoler {
return c.subProtocols
}
"github.com/bytom/vapor/protocol/state"
)
+// predefine errors
var (
ErrNotFoundConsensusResult = errors.New("can't find the vote result by given sequence")
)
ErrDustTx = errors.New("transaction is dust tx")
)
+// DustFilterer is inerface for dust transaction filter rule
type DustFilterer interface {
IsDust(tx *types.Tx) bool
}
+// TxMsgEvent is message wrap for subscribe event
type TxMsgEvent struct{ TxMsg *TxPoolMsg }
// TxDesc store tx and related info for mining strategy
return errors.Wrapf(validateResult.err, "validate of transaction %d of %d", i, len(b.Transactions))
}
- // for support flash swap running on vapor, status fail txs need to be
- // rejected. Or the attacker can steal BTM from any BTM/* trade pair by
- // using status fail charge fee rule.
- if b.Height >= consensus.ActiveNetParams.MovStartHeight && validateResult.err != nil {
- return errors.New("the chain currently didn't support status fail tx")
- }
-
if err := b.TransactionStatus.SetStatus(i, validateResult.err != nil); err != nil {
return err
}
consensus.ActiveNetParams.RoundVoteBlockNums = c.RoundVoteBlockNums
movDB := dbm.NewDB("mov_db", "leveldb", "mov_db")
- movCore := mov.NewMovCoreWithDB(movDatabase.NewLevelDBMovStore(movDB), c.movStartHeight)
+ movCore := mov.NewCoreWithDB(movDatabase.NewLevelDBMovStore(movDB), c.movStartHeight)
blockDB := dbm.NewDB("block_db", "leveldb", "block_db")
store := database.NewStore(blockDB)