• R/O
  • HTTP
  • SSH
  • HTTPS

vapor: Commit

Golang implemented sidechain for Bytom


Commit MetaInfo

Revisione4b588587cef193de8776ebd2dd8d1a0f8cd3674 (tree)
Time2020-09-16 12:16:56
Authoroys <ouyang@ouya...>
Commiteroys

Log Message

merge master

Change Summary

Incremental Difference

--- a/api/nodeinfo.go
+++ b/api/nodeinfo.go
@@ -24,16 +24,17 @@ type VersionInfo struct {
2424
2525 // NetInfo indicate net information
2626 type NetInfo struct {
27- Listening bool `json:"listening"`
28- Syncing bool `json:"syncing"`
29- Mining bool `json:"mining"`
30- NodeXPub string `json:"node_xpub"`
31- FedAddress string `json:"federation_address"`
32- PeerCount int `json:"peer_count"`
33- CurrentBlock uint64 `json:"current_block"`
34- HighestBlock uint64 `json:"highest_block"`
35- NetWorkID string `json:"network_id"`
36- Version *VersionInfo `json:"version_info"`
27+ Listening bool `json:"listening"`
28+ Syncing bool `json:"syncing"`
29+ Mining bool `json:"mining"`
30+ NodeXPub string `json:"node_xpub"`
31+ FedAddress string `json:"federation_address"`
32+ PeerCount int `json:"peer_count"`
33+ CurrentBlock uint64 `json:"current_block"`
34+ IrreversibleBlock uint64 `json:"irreversible_block"`
35+ HighestBlock uint64 `json:"highest_block"`
36+ NetWorkID string `json:"network_id"`
37+ Version *VersionInfo `json:"version_info"`
3738 }
3839
3940 // GetNodeInfo return net information
@@ -48,14 +49,15 @@ func (a *API) GetNodeInfo() *NetInfo {
4849 }
4950
5051 info := &NetInfo{
51- Listening: a.sync.IsListening(),
52- Syncing: !a.sync.IsCaughtUp(),
53- Mining: a.blockProposer.IsProposing(),
54- NodeXPub: nodeXPub.String(),
55- FedAddress: address.EncodeAddress(),
56- PeerCount: a.sync.PeerCount(),
57- CurrentBlock: a.chain.BestBlockHeight(),
58- NetWorkID: a.sync.GetNetwork(),
52+ Listening: a.sync.IsListening(),
53+ Syncing: !a.sync.IsCaughtUp(),
54+ Mining: a.blockProposer.IsProposing(),
55+ NodeXPub: nodeXPub.String(),
56+ FedAddress: address.EncodeAddress(),
57+ PeerCount: a.sync.PeerCount(),
58+ CurrentBlock: a.chain.BestBlockHeight(),
59+ IrreversibleBlock: a.chain.LastIrreversibleHeader().Height,
60+ NetWorkID: a.sync.GetNetwork(),
5961 Version: &VersionInfo{
6062 Version: version.Version,
6163 Update: version.Status.VersionStatus(),
--- a/application/mov/database/mov_store.go
+++ b/application/mov/database/mov_store.go
@@ -12,8 +12,12 @@ import (
1212 "github.com/bytom/vapor/protocol/bc/types"
1313 )
1414
15+// ErrNotInitDBState represent the database state of mov store is not initialized
16+var ErrNotInitDBState = errors.New("database state of mov store is not initialized")
17+
1518 // MovStore is the interface for mov's persistent storage
1619 type MovStore interface {
20+ Clear()
1721 GetMovDatabaseState() (*common.MovDatabaseState, error)
1822 InitDBState(height uint64, hash *bc.Hash) error
1923 ListOrders(orderAfter *common.Order) ([]*common.Order, error)
@@ -89,6 +93,19 @@ func NewLevelDBMovStore(db dbm.DB) *LevelDBMovStore {
8993 return &LevelDBMovStore{db: db}
9094 }
9195
96+// Clear will clear all the data of store
97+func (m *LevelDBMovStore) Clear() {
98+ batch := m.db.NewBatch()
99+
100+ iter := m.db.Iterator()
101+ defer iter.Release()
102+
103+ for iter.Next() {
104+ batch.Delete(iter.Key())
105+ }
106+ batch.Write()
107+}
108+
92109 // GetMovDatabaseState return the current DB's image status
93110 func (m *LevelDBMovStore) GetMovDatabaseState() (*common.MovDatabaseState, error) {
94111 if value := m.db.Get(bestMatchStore); value != nil {
@@ -96,7 +113,7 @@ func (m *LevelDBMovStore) GetMovDatabaseState() (*common.MovDatabaseState, error
96113 return state, json.Unmarshal(value, state)
97114 }
98115
99- return nil, errors.New("don't find state of mov-database")
116+ return nil, ErrNotInitDBState
100117 }
101118
102119 // InitDBState set the DB's image status
--- a/application/mov/match/engine.go
+++ b/application/mov/match/engine.go
@@ -62,20 +62,44 @@ func (e *Engine) NextMatchedTx(tradePairs ...*common.TradePair) (*types.Tx, erro
6262 return tx, nil
6363 }
6464
65-func (e *Engine) addMatchTxFeeOutput(txData *types.TxData, refunds []RefundAssets, fees []*bc.AssetAmount) error {
65+func (e *Engine) addMatchTxFeeOutput(txData *types.TxData, fees []*bc.AssetAmount) error {
6666 for _, feeAmount := range fees {
6767 txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*feeAmount.AssetId, feeAmount.Amount, e.rewardProgram))
6868 }
6969
70- for i, refund := range refunds {
71- // each trading participant may be refunded multiple assets
72- for _, assetAmount := range refund {
73- contractArgs, err := segwit.DecodeP2WMCProgram(txData.Inputs[i].ControlProgram())
74- if err != nil {
75- return err
76- }
70+ refoundAmount := map[bc.AssetID]uint64{}
71+ assetIDs := []bc.AssetID{}
72+ refoundScript := [][]byte{}
73+ for _, input := range txData.Inputs {
74+ refoundAmount[input.AssetID()] += input.Amount()
75+ contractArgs, err := segwit.DecodeP2WMCProgram(input.ControlProgram())
76+ if err != nil {
77+ return err
78+ }
7779
78- txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*assetAmount.AssetId, assetAmount.Amount, contractArgs.SellerProgram))
80+ assetIDs = append(assetIDs, input.AssetID())
81+ refoundScript = append(refoundScript, contractArgs.SellerProgram)
82+ }
83+
84+ for _, output := range txData.Outputs {
85+ assetAmount := output.AssetAmount()
86+ refoundAmount[*assetAmount.AssetId] -= assetAmount.Amount
87+ }
88+
89+ refoundCount := len(refoundScript)
90+ for _, assetID := range assetIDs {
91+ amount := refoundAmount[assetID]
92+ averageAmount := amount / uint64(refoundCount)
93+ if averageAmount == 0 {
94+ averageAmount = 1
95+ }
96+
97+ for i := 0; i < refoundCount && amount > 0; i++ {
98+ if i == refoundCount-1 {
99+ averageAmount = amount
100+ }
101+ txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(assetID, averageAmount, refoundScript[i]))
102+ amount -= averageAmount
79103 }
80104 }
81105 return nil
@@ -106,11 +130,11 @@ func (e *Engine) buildMatchTx(orders []*common.Order) (*types.Tx, error) {
106130
107131 receivedAmounts, priceDiffs := CalcReceivedAmount(orders)
108132 allocatedAssets := e.feeStrategy.Allocate(receivedAmounts, priceDiffs)
109- if err := addMatchTxOutput(txData, orders, receivedAmounts, allocatedAssets.Receives); err != nil {
133+ if err := addMatchTxOutput(txData, orders, receivedAmounts, allocatedAssets); err != nil {
110134 return nil, err
111135 }
112136
113- if err := e.addMatchTxFeeOutput(txData, allocatedAssets.Refunds, allocatedAssets.Fees); err != nil {
137+ if err := e.addMatchTxFeeOutput(txData, allocatedAssets.Fees); err != nil {
114138 return nil, err
115139 }
116140
@@ -123,22 +147,24 @@ func (e *Engine) buildMatchTx(orders []*common.Order) (*types.Tx, error) {
123147 return types.NewTx(*txData), nil
124148 }
125149
126-func addMatchTxOutput(txData *types.TxData, orders []*common.Order, receivedAmounts, deductFeeReceives []*bc.AssetAmount) error {
150+func addMatchTxOutput(txData *types.TxData, orders []*common.Order, receivedAmounts []*bc.AssetAmount, allocatedAssets *AllocatedAssets) error {
127151 for i, order := range orders {
128152 contractArgs, err := segwit.DecodeP2WMCProgram(order.Utxo.ControlProgram)
129153 if err != nil {
130154 return err
131155 }
132156
133- requestAmount := CalcRequestAmount(order.Utxo.Amount, contractArgs.RatioNumerator, contractArgs.RatioDenominator)
134157 receivedAmount := receivedAmounts[i].Amount
135158 shouldPayAmount := calcShouldPayAmount(receivedAmount, contractArgs.RatioNumerator, contractArgs.RatioDenominator)
136- isPartialTrade := requestAmount > receivedAmount
137159
138- setMatchTxArguments(txData.Inputs[i], isPartialTrade, len(txData.Outputs), receivedAmounts[i].Amount)
139- txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*order.ToAssetID, deductFeeReceives[i].Amount, contractArgs.SellerProgram))
160+ requestAmount := CalcRequestAmount(order.Utxo.Amount, order.RatioNumerator, order.RatioDenominator)
161+ exchangeAmount := order.Utxo.Amount - shouldPayAmount
162+ isPartialTrade := requestAmount > receivedAmount && CalcRequestAmount(exchangeAmount, contractArgs.RatioNumerator, contractArgs.RatioDenominator) >= 1
163+
164+ setMatchTxArguments(txData.Inputs[i], isPartialTrade, len(txData.Outputs), receivedAmount)
165+ txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*order.ToAssetID, allocatedAssets.Receives[i].Amount, contractArgs.SellerProgram))
140166 if isPartialTrade {
141- txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*order.FromAssetID, order.Utxo.Amount-shouldPayAmount, order.Utxo.ControlProgram))
167+ txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*order.FromAssetID, exchangeAmount, order.Utxo.ControlProgram))
142168 }
143169 }
144170 return nil
@@ -181,10 +207,9 @@ func CalcReceivedAmount(orders []*common.Order) ([]*bc.AssetAmount, []*bc.AssetA
181207
182208 for i, receivedAmount := range receivedAmounts {
183209 oppositeShouldPayAmount := shouldPayAmounts[calcOppositeIndex(len(orders), i)]
210+ priceDiffs = append(priceDiffs, &bc.AssetAmount{AssetId: oppositeShouldPayAmount.AssetId, Amount: 0})
184211 if oppositeShouldPayAmount.Amount > receivedAmount.Amount {
185- assetID := oppositeShouldPayAmount.AssetId
186- amount := oppositeShouldPayAmount.Amount - receivedAmount.Amount
187- priceDiffs = append(priceDiffs, &bc.AssetAmount{AssetId: assetID, Amount: amount})
212+ priceDiffs[i].Amount = oppositeShouldPayAmount.Amount - receivedAmount.Amount
188213 }
189214 }
190215 return receivedAmounts, priceDiffs
--- a/application/mov/match/fee_strategy.go
+++ b/application/mov/match/fee_strategy.go
@@ -15,13 +15,9 @@ var (
1515 // AllocatedAssets represent reallocated assets after calculating fees
1616 type AllocatedAssets struct {
1717 Receives []*bc.AssetAmount
18- Refunds []RefundAssets
1918 Fees []*bc.AssetAmount
2019 }
2120
22-// RefundAssets represent alias for assetAmount array, because each transaction participant can be refunded multiple assets
23-type RefundAssets []*bc.AssetAmount
24-
2521 // FeeStrategy used to indicate how to charge a matching fee
2622 type FeeStrategy interface {
2723 // Allocate will allocate the price differential in matching transaction to the participants and the fee
@@ -35,7 +31,7 @@ type FeeStrategy interface {
3531 }
3632
3733 // DefaultFeeStrategy represent the default fee charge strategy
38-type DefaultFeeStrategy struct {}
34+type DefaultFeeStrategy struct{}
3935
4036 // NewDefaultFeeStrategy return a new instance of DefaultFeeStrategy
4137 func NewDefaultFeeStrategy() *DefaultFeeStrategy {
@@ -44,46 +40,20 @@ func NewDefaultFeeStrategy() *DefaultFeeStrategy {
4440
4541 // Allocate will allocate the price differential in matching transaction to the participants and the fee
4642 func (d *DefaultFeeStrategy) Allocate(receiveAmounts, priceDiffs []*bc.AssetAmount) *AllocatedAssets {
47- feeMap := make(map[bc.AssetID]uint64)
48- for _, priceDiff := range priceDiffs {
49- feeMap[*priceDiff.AssetId] = priceDiff.Amount
50- }
51-
52- var fees []*bc.AssetAmount
53- refunds := make([]RefundAssets, len(receiveAmounts))
5443 receives := make([]*bc.AssetAmount, len(receiveAmounts))
44+ fees := make([]*bc.AssetAmount, len(receiveAmounts))
5545
5646 for i, receiveAmount := range receiveAmounts {
57- amount := receiveAmount.Amount
58- minFeeAmount := d.calcMinFeeAmount(amount)
59- receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: amount - minFeeAmount}
60- feeMap[*receiveAmount.AssetId] += minFeeAmount
61-
62- maxFeeAmount := d.calcMaxFeeAmount(amount)
63- feeAmount, reminder := feeMap[*receiveAmount.AssetId], uint64(0)
64- if feeAmount > maxFeeAmount {
65- reminder = feeAmount - maxFeeAmount
66- feeAmount = maxFeeAmount
47+ standFee := d.calcMinFeeAmount(receiveAmount.Amount)
48+ fee := standFee + priceDiffs[i].Amount
49+ if maxFeeAmount := d.calcMaxFeeAmount(receiveAmount.Amount); fee > maxFeeAmount {
50+ fee = maxFeeAmount
6751 }
6852
69- fees = append(fees, &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: feeAmount})
70-
71- // There is the remaining amount after paying the handling fee, assign it evenly to participants in the transaction
72- averageAmount := reminder / uint64(len(receiveAmounts))
73- if averageAmount == 0 {
74- averageAmount = 1
75- }
76-
77- for j := 0; j < len(receiveAmounts) && reminder > 0; j++ {
78- refundAmount := averageAmount
79- if j == len(receiveAmounts)-1 {
80- refundAmount = reminder
81- }
82- refunds[j] = append(refunds[j], &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: refundAmount})
83- reminder -= averageAmount
84- }
53+ receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: receiveAmount.Amount - standFee}
54+ fees[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: fee}
8555 }
86- return &AllocatedAssets{Receives: receives, Refunds: refunds, Fees: fees}
56+ return &AllocatedAssets{Receives: receives, Fees: fees}
8757 }
8858
8959 // Validate verify that the fee charged for a matching transaction is correct
--- a/application/mov/mock/mock.go
+++ b/application/mov/mock/mock.go
@@ -453,10 +453,10 @@ var (
453453 types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 25, RewardProgram),
454454 types.NewIntraChainOutput(*Eth2BtcOrders[3].ToAssetID, 1, RewardProgram),
455455 // refund
456- types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251")),
457456 types.NewIntraChainOutput(*Eth2BtcOrders[3].ToAssetID, 3, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251")),
458- types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19256")),
459457 types.NewIntraChainOutput(*Eth2BtcOrders[3].ToAssetID, 3, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19256")),
458+ types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251")),
459+ types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19256")),
460460 },
461461 }),
462462 }
--- a/application/mov/mock/mock_mov_store.go
+++ b/application/mov/mock/mock_mov_store.go
@@ -30,6 +30,12 @@ func NewMovStore(tradePairs []*common.TradePair, orders []*common.Order) *MovSto
3030 }
3131 }
3232
33+func (m *MovStore) Clear() {
34+ m.tradePairs = nil
35+ m.dbState = nil
36+ m.orderMap = make(map[string][]*common.Order)
37+}
38+
3339 func (m *MovStore) GetMovDatabaseState() (*common.MovDatabaseState, error) {
3440 return m.dbState, nil
3541 }
--- a/application/mov/mov_core.go
+++ b/application/mov/mov_core.go
@@ -11,11 +11,14 @@ import (
1111 "github.com/bytom/vapor/consensus/segwit"
1212 dbm "github.com/bytom/vapor/database/leveldb"
1313 "github.com/bytom/vapor/errors"
14+
15+ "github.com/bytom/vapor/protocol"
1416 "github.com/bytom/vapor/protocol/bc"
1517 "github.com/bytom/vapor/protocol/bc/types"
1618 )
1719
1820 var (
21+ errChainStatusHasAlreadyInit = errors.New("mov chain status has already initialized")
1922 errInvalidTradePairs = errors.New("The trade pairs in the tx input is invalid")
2023 errStatusFailMustFalse = errors.New("status fail of transaction does not allow to be true")
2124 errInputProgramMustP2WMCScript = errors.New("input program of trade tx must p2wmc script")
@@ -57,7 +60,7 @@ func (m *Core) ApplyBlock(block *types.Block) error {
5760
5861 if block.Height == m.startBlockHeight {
5962 blockHash := block.Hash()
60- return m.movStore.InitDBState(block.Height, &blockHash)
63+ return m.InitChainStatus(&blockHash)
6164 }
6265
6366 if err := m.validateMatchedTxSequence(block.Transactions); err != nil {
@@ -98,6 +101,10 @@ func (m *Core) BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft
98101 // ChainStatus return the current block height and block hash in dex core
99102 func (m *Core) ChainStatus() (uint64, *bc.Hash, error) {
100103 state, err := m.movStore.GetMovDatabaseState()
104+ if err == database.ErrNotInitDBState {
105+ return 0, nil, protocol.ErrNotInitSubProtocolChainStatus
106+ }
107+
101108 if err != nil {
102109 return 0, nil, err
103110 }
@@ -112,6 +119,11 @@ func (m *Core) DetachBlock(block *types.Block) error {
112119 return nil
113120 }
114121
122+ if block.Height == m.startBlockHeight {
123+ m.movStore.Clear()
124+ return nil
125+ }
126+
115127 deleteOrders, addOrders, err := decodeTxsOrders(block.Transactions)
116128 if err != nil {
117129 return err
@@ -120,6 +132,15 @@ func (m *Core) DetachBlock(block *types.Block) error {
120132 return m.movStore.ProcessOrders(addOrders, deleteOrders, &block.BlockHeader)
121133 }
122134
135+// InitChainStatus used to init the start block height and start block hash to store
136+func (m *Core) InitChainStatus(startHash *bc.Hash) error {
137+ if _, err := m.movStore.GetMovDatabaseState(); err == nil {
138+ return errChainStatusHasAlreadyInit
139+ }
140+
141+ return m.movStore.InitDBState(m.startBlockHeight, startHash)
142+}
143+
123144 // IsDust block the transaction that are not generated by the match engine
124145 func (m *Core) IsDust(tx *types.Tx) bool {
125146 for _, input := range tx.Inputs {
@@ -162,11 +183,11 @@ func (m *Core) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHe
162183 }
163184
164185 if common.IsMatchedTx(tx) {
165- if err := validateMatchedTx(tx, verifyResult, blockHeight); err != nil {
186+ if err := validateMatchedTx(tx, blockHeight); err != nil {
166187 return err
167188 }
168189 } else if common.IsCancelOrderTx(tx) {
169- if err := validateCancelOrderTx(tx, verifyResult); err != nil {
190+ if err := validateCancelOrderTx(tx); err != nil {
170191 return err
171192 }
172193 }
@@ -220,7 +241,7 @@ func calcFeeAmount(matchedTx *types.Tx) (map[bc.AssetID]*matchedTxFee, error) {
220241 return assetFeeMap, nil
221242 }
222243
223-func validateCancelOrderTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error {
244+func validateCancelOrderTx(tx *types.Tx) error {
224245 for _, input := range tx.Inputs {
225246 if !segwit.IsP2WMCScript(input.ControlProgram()) {
226247 return errInputProgramMustP2WMCScript
@@ -253,7 +274,7 @@ func validateMagneticContractArgs(fromAssetAmount bc.AssetAmount, program []byte
253274 return nil
254275 }
255276
256-func validateMatchedTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error {
277+func validateMatchedTx(tx *types.Tx, blockHeight uint64) error {
257278 fromAssetIDMap := make(map[string]bool)
258279 toAssetIDMap := make(map[string]bool)
259280 for i, input := range tx.Inputs {
@@ -491,7 +512,7 @@ func mergeOrders(addOrderMap, deleteOrderMap map[string]*common.Order) ([]*commo
491512 func getRewardProgram(height uint64) (string, bool) {
492513 rewardPrograms := consensus.ActiveNetParams.MovRewardPrograms
493514 if len(rewardPrograms) == 0 {
494- return "", false
515+ return "51", false
495516 }
496517
497518 var program string
--- a/blockchain/pseudohsm/pseudohsm.go
+++ b/blockchain/pseudohsm/pseudohsm.go
@@ -94,7 +94,7 @@ func (h *HSM) ImportKeyFromMnemonic(alias string, auth string, mnemonic string,
9494 return nil, mnem.ErrInvalidMnemonic
9595 }
9696
97- xpub, err := h.createKeyFromMnemonic(alias, auth, mnemonic)
97+ xpub, err := h.createKeyFromMnemonic(normalizedAlias, auth, mnemonic)
9898 if err != nil {
9999 return nil, err
100100 }
--- a/config/toml.go
+++ b/config/toml.go
@@ -32,7 +32,7 @@ var mainNetConfigTmpl = `chain_id = "mainnet"
3232 laddr = "tcp://0.0.0.0:56656"
3333 seeds = "47.103.79.68:56656,47.103.13.86:56656,47.102.193.119:56656,47.103.17.22:56656"
3434 [cross_chain]
35-asset_whitelist = ""
35+asset_whitelist = "184e1cc4ee4845023888810a79eed7a42c02c544cf2c61ceac05e176d575bd46,78de44ffa1bce37b757c9eae8925b5f199dc4621b412ef0f3f46168865284a93,bda946b3110fa46fd94346ce3f05f0760f1b9de72e238835bc4d19f9d64f1742,25f2069140fa3ff4d6e0dc1d0fcaa11ace01eb721f115f0f1a5a3782db597fb1,c4644dd6643475d57ed624f63129ab815f282b61f4bb07646d73423a6e1a1563"
3636 `
3737
3838 var testNetConfigTmpl = `chain_id = "testnet"
--- a/consensus/general.go
+++ b/consensus/general.go
@@ -109,7 +109,7 @@ type Params struct {
109109 // ProducerSubsidys defines the producer subsidy by block height
110110 ProducerSubsidys []ProducerSubsidy
111111
112- SoftForkPoint map[uint64]uint64
112+ SoftForkPoint map[uint64]uint64
113113
114114 // Mov will only start when the block height is greater than this value
115115 MovStartHeight uint64
@@ -156,9 +156,10 @@ var MainNetParams = Params{
156156 Checkpoints: []Checkpoint{},
157157 ProducerSubsidys: []ProducerSubsidy{
158158 {BeginBlock: 1, EndBlock: 63072000, Subsidy: 9512938},
159+ {BeginBlock: 63072001, EndBlock: 126144000, Subsidy: 9512938},
159160 },
160161 SoftForkPoint: map[uint64]uint64{SoftFork001: 10461600},
161- MovStartHeight: 43354800,
162+ MovStartHeight: 42884800,
162163 MovRewardPrograms: []MovRewardProgram{
163164 {
164165 BeginBlock: 1,
--- /dev/null
+++ b/docs/release-notes/release-notes-1.1.0.md
@@ -0,0 +1,41 @@
1+Vapor version 1.1.0 is now available from:
2+
3+ https://github.com/Bytom/vapor/releases/tag/v1.1.0
4+
5+
6+Please report bugs using the issue tracker at github:
7+
8+ https://github.com/Bytom/vapor/issues
9+
10+
11+
12+1.1.0 changelog
13+================
14+__Vapor Node__
15+
16++ `PR #518`
17+ - Support Mov on-chain asset exchange protocol.
18+ - Support cross chain for the open federation asset.
19++ `PR #517`
20+ - Prevent network timeout issues for fast network sync in the latency environment.
21++ `PR #496`
22+ - Add rollback function to handle the edge fork case.
23+
24+
25+Credits
26+--------
27+
28+Thanks to everyone who directly contributed to this release:
29+
30+- Colt-Z
31+- HAOYUatHZ
32+- ipqhjjybj
33+- langyu
34+- Paladz
35+- shenao78
36+- shengling2008
37+- oysheng
38+- zcc0721
39+- ZhitingLin
40+
41+And everyone who helped test.
\ No newline at end of file
--- /dev/null
+++ b/docs/release-notes/release-notes-1.1.2.md
@@ -0,0 +1,40 @@
1+Vapor version 1.1.2 is now available from:
2+
3+ https://github.com/Bytom/vapor/releases/tag/v1.1.2
4+
5+
6+Please report bugs using the issue tracker at github:
7+
8+ https://github.com/Bytom/vapor/issues
9+
10+
11+
12+1.1.2 changelog
13+================
14+__Vapor Node__
15+
16++ `PR #533`
17+ - Support BTC asset cross-chain.
18++ `PR #527`
19+ - Support update to mov node for the nodes not updated at specified time and add some related test case.
20++ `PR #523`
21+ - Fix the refund from matching transaction may result in asset unbalance problem.
22+
23+
24+Credits
25+--------
26+
27+Thanks to everyone who directly contributed to this release:
28+
29+- Colt-Z
30+- HAOYUatHZ
31+- ipqhjjybj
32+- langyu
33+- Paladz
34+- shenao78
35+- shengling2008
36+- oysheng
37+- zcc0721
38+- ZhitingLin
39+
40+And everyone who helped test.
\ No newline at end of file
--- /dev/null
+++ b/docs/release-notes/release-notes-1.1.4.md
@@ -0,0 +1,39 @@
1+Vapor version 1.1.4 is now available from:
2+
3+ https://github.com/Bytom/vapor/releases/tag/v1.1.4
4+
5+
6+Please report bugs using the issue tracker at github:
7+
8+ https://github.com/Bytom/vapor/issues
9+
10+
11+
12+1.1.4 changelog
13+================
14+__Vapor Node__
15+
16++ `PR #538`
17+ - Add the height interval of the next round of block rewards.
18++ `PR #536`
19+ - Support cross-chain of USDC and DAI.
20++ `PR #535`
21+ - Fix the bug when the trader only received 1 unit of assets during the match transaction and the magnet contract report error.
22+
23+
24+Credits
25+--------
26+
27+Thanks to everyone who directly contributed to this release:
28+
29+- Colt-Z
30+- HAOYUatHZ
31+- ipqhjjybj
32+- langyu
33+- Paladz
34+- shenao78
35+- oysheng
36+- zcc0721
37+- ZhitingLin
38+
39+And everyone who helped test.
\ No newline at end of file
--- a/netsync/chainmgr/block_keeper.go
+++ b/netsync/chainmgr/block_keeper.go
@@ -7,8 +7,10 @@ import (
77
88 "github.com/bytom/vapor/consensus"
99 dbm "github.com/bytom/vapor/database/leveldb"
10+ "github.com/bytom/vapor/errors"
1011 "github.com/bytom/vapor/netsync/peers"
1112 "github.com/bytom/vapor/p2p/security"
13+ "github.com/bytom/vapor/protocol"
1214 "github.com/bytom/vapor/protocol/bc"
1315 "github.com/bytom/vapor/protocol/bc/types"
1416 )
@@ -170,7 +172,9 @@ func (bk *blockKeeper) regularBlockSync() error {
170172
171173 isOrphan, err := bk.chain.ProcessBlock(block)
172174 if err != nil {
173- bk.peers.ProcessIllegal(bk.syncPeer.ID(), security.LevelMsgIllegal, err.Error())
175+ if errors.Root(err) != protocol.ErrDoubleSignBlock {
176+ bk.peers.ProcessIllegal(bk.syncPeer.ID(), security.LevelMsgIllegal, err.Error())
177+ }
174178 return err
175179 }
176180
--- a/netsync/chainmgr/block_process.go
+++ b/netsync/chainmgr/block_process.go
@@ -8,6 +8,7 @@ import (
88 "github.com/bytom/vapor/errors"
99 "github.com/bytom/vapor/netsync/peers"
1010 "github.com/bytom/vapor/p2p/security"
11+ "github.com/bytom/vapor/protocol"
1112 )
1213
1314 var errOrphanBlock = errors.New("fast sync inserting orphan block")
@@ -33,7 +34,7 @@ func (bp *blockProcessor) insert(blockStorage *blockStorage) error {
3334 return errOrphanBlock
3435 }
3536
36- if err != nil {
37+ if err != nil && errors.Root(err) != protocol.ErrDoubleSignBlock {
3738 bp.peers.ProcessIllegal(blockStorage.peerID, security.LevelMsgIllegal, err.Error())
3839 }
3940 return err
--- a/netsync/consensusmgr/handle.go
+++ b/netsync/consensusmgr/handle.go
@@ -5,10 +5,12 @@ import (
55
66 "github.com/sirupsen/logrus"
77
8+ "github.com/bytom/vapor/errors"
89 "github.com/bytom/vapor/event"
910 "github.com/bytom/vapor/netsync/peers"
1011 "github.com/bytom/vapor/p2p"
1112 "github.com/bytom/vapor/p2p/security"
13+ "github.com/bytom/vapor/protocol"
1214 "github.com/bytom/vapor/protocol/bc"
1315 "github.com/bytom/vapor/protocol/bc/types"
1416 )
@@ -109,8 +111,9 @@ func (m *Manager) handleBlockSignatureMsg(peerID string, msg *BlockSignatureMsg)
109111 m.peers.MarkBlockSignature(peerID, msg.Signature)
110112 blockHash := bc.NewHash(msg.BlockHash)
111113 if err := m.chain.ProcessBlockSignature(msg.Signature, msg.PubKey, &blockHash); err != nil {
112- m.peers.ProcessIllegal(peerID, security.LevelMsgIllegal, err.Error())
113- return
114+ if errors.Root(err) != protocol.ErrDoubleSignBlock {
115+ m.peers.ProcessIllegal(peerID, security.LevelMsgIllegal, err.Error())
116+ }
114117 }
115118 }
116119
--- a/node/node.go
+++ b/node/node.go
@@ -5,6 +5,7 @@ import (
55 "errors"
66 "net"
77 "net/http"
8+
89 // debug tool
910 _ "net/http/pprof"
1011 "path/filepath"
@@ -88,7 +89,7 @@ func NewNode(config *cfg.Config) *Node {
8889 movCore := mov.NewCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
8990 assetFilter := protocol.NewAssetFilter(config.CrossChain.AssetWhitelist)
9091 txPool := protocol.NewTxPool(store, []protocol.DustFilterer{movCore, assetFilter}, dispatcher)
91- chain, err := protocol.NewChain(store, txPool, []protocol.Protocoler{movCore}, dispatcher)
92+ chain, err := protocol.NewChain(store, txPool, []protocol.SubProtocol{movCore}, dispatcher)
9293 if err != nil {
9394 cmn.Exit(cmn.Fmt("Failed to create chain structure: %v", err))
9495 }
@@ -180,7 +181,7 @@ func Rollback(config *cfg.Config, targetHeight uint64) error {
180181 dispatcher := event.NewDispatcher()
181182 movCore := mov.NewCore(config.DBBackend, config.DBDir(), consensus.ActiveNetParams.MovStartHeight)
182183 txPool := protocol.NewTxPool(store, []protocol.DustFilterer{movCore}, dispatcher)
183- chain, err := protocol.NewChain(store, txPool, []protocol.Protocoler{movCore}, dispatcher)
184+ chain, err := protocol.NewChain(store, txPool, []protocol.SubProtocol{movCore}, dispatcher)
184185 if err != nil {
185186 return err
186187 }
--- a/proposal/proposal.go
+++ b/proposal/proposal.go
@@ -334,7 +334,7 @@ func (b *blockBuilder) preValidateTxs(txs []*types.Tx, chain *protocol.Chain, vi
334334 return results, gasLeft
335335 }
336336
337-func (b *blockBuilder) validateBySubProtocols(tx *types.Tx, statusFail bool, subProtocols []protocol.Protocoler) error {
337+func (b *blockBuilder) validateBySubProtocols(tx *types.Tx, statusFail bool, subProtocols []protocol.SubProtocol) error {
338338 for _, subProtocol := range subProtocols {
339339 verifyResult := &bc.TxVerifyResult{StatusFail: statusFail}
340340 if err := subProtocol.ValidateTx(tx, verifyResult, b.block.Height); err != nil {
--- a/protocol/bbft.go
+++ b/protocol/bbft.go
@@ -20,9 +20,9 @@ const (
2020 )
2121
2222 var (
23- errDoubleSignBlock = errors.New("the consensus is double sign in same height of different block")
23+ // ErrDoubleSignBlock represent the consensus is double sign in same height of different block
24+ ErrDoubleSignBlock = errors.New("the consensus is double sign in same height of different block")
2425 errInvalidSignature = errors.New("the signature of block is invalid")
25- errSignForkChain = errors.New("can not sign fork before the irreversible block")
2626 )
2727
2828 func signCacheKey(blockHash, pubkey string) string {
@@ -53,7 +53,7 @@ func (c *Chain) checkDoubleSign(bh *types.BlockHeader, xPub string) error {
5353 }
5454
5555 if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
56- return errDoubleSignBlock
56+ return ErrDoubleSignBlock
5757 }
5858 }
5959 return nil
@@ -140,7 +140,7 @@ func (c *Chain) validateSign(block *types.Block) error {
140140 }
141141 }
142142
143- if err := c.checkNodeSign(&block.BlockHeader, node, block.Get(node.Order)); err == errDoubleSignBlock {
143+ if err := c.checkNodeSign(&block.BlockHeader, node, block.Get(node.Order)); err == ErrDoubleSignBlock {
144144 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubKey": pubKey}).Warn("the consensus node double sign the same height of different block")
145145 // if the blocker double sign & become the mainchain, that means
146146 // all the side chain will reject the main chain make the chain
@@ -149,6 +149,8 @@ func (c *Chain) validateSign(block *types.Block) error {
149149 block.BlockWitness.Delete(node.Order)
150150 continue
151151 }
152+
153+ return err
152154 } else if err != nil {
153155 return err
154156 }
@@ -206,7 +208,9 @@ func (c *Chain) ProcessBlockSignature(signature, xPub []byte, blockHash *bc.Hash
206208
207209 // SignBlockHeader signing the block if current node is consensus node
208210 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) error {
211+ c.cond.L.Lock()
209212 _, err := c.signBlockHeader(blockHeader)
213+ c.cond.L.Unlock()
210214 return err
211215 }
212216
@@ -244,7 +248,7 @@ func (c *Chain) signBlockHeader(blockHeader *types.BlockHeader) ([]byte, error)
244248 return nil, nil
245249 }
246250
247- if err := c.checkDoubleSign(blockHeader, node.XPub.String()); err == errDoubleSignBlock {
251+ if err := c.checkDoubleSign(blockHeader, node.XPub.String()); err == ErrDoubleSignBlock {
248252 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String()}).Warn("current node has double sign the block")
249253 return nil, nil
250254 } else if err != nil {
--- a/protocol/protocol.go
+++ b/protocol/protocol.go
@@ -19,12 +19,19 @@ const (
1919 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
2020 )
2121
22-// Protocoler is interface for layer 2 consensus protocol
23-type Protocoler interface {
22+// ErrNotInitSubProtocolChainStatus represent the node state of sub protocol has not been initialized
23+var ErrNotInitSubProtocolChainStatus = errors.New("node state of sub protocol has not been initialized")
24+
25+// SubProtocol is interface for layer 2 consensus protocol
26+type SubProtocol interface {
2427 Name() string
2528 StartHeight() uint64
2629 BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error)
30+
31+ // ChainStatus return the the current block height and block hash of sub protocol.
32+ // it will return ErrNotInitSubProtocolChainStatus if not initialized.
2733 ChainStatus() (uint64, *bc.Hash, error)
34+ InitChainStatus(*bc.Hash) error
2835 ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error
2936 ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error
3037 ApplyBlock(block *types.Block) error
@@ -37,7 +44,7 @@ type Chain struct {
3744 txPool *TxPool
3845 store Store
3946 processBlockCh chan *processBlockMsg
40- subProtocols []Protocoler
47+ subProtocols []SubProtocol
4148
4249 signatureCache *common.Cache
4350 eventDispatcher *event.Dispatcher
@@ -50,7 +57,7 @@ type Chain struct {
5057 }
5158
5259 // NewChain returns a new Chain using store as the underlying storage.
53-func NewChain(store Store, txPool *TxPool, subProtocols []Protocoler, eventDispatcher *event.Dispatcher) (*Chain, error) {
60+func NewChain(store Store, txPool *TxPool, subProtocols []SubProtocol, eventDispatcher *event.Dispatcher) (*Chain, error) {
5461 knownTxs, _ := common.NewOrderedSet(maxKnownTxs)
5562 c := &Chain{
5663 orphanManage: NewOrphanManage(),
@@ -175,7 +182,7 @@ func (c *Chain) InMainChain(hash bc.Hash) bool {
175182 }
176183
177184 // SubProtocols return list of layer 2 consensus protocol
178-func (c *Chain) SubProtocols() []Protocoler {
185+func (c *Chain) SubProtocols() []SubProtocol {
179186 return c.subProtocols
180187 }
181188
@@ -215,14 +222,25 @@ func (c *Chain) markTransactions(txs ...*types.Tx) {
215222 }
216223 }
217224
218-func (c *Chain) syncProtocolStatus(subProtocol Protocoler) error {
225+func (c *Chain) syncProtocolStatus(subProtocol SubProtocol) error {
219226 if c.bestBlockHeader.Height < subProtocol.StartHeight() {
220227 return nil
221228 }
222229
223230 protocolHeight, protocolHash, err := subProtocol.ChainStatus()
224- if err != nil {
225- return errors.Wrap(err, "failed on get sub protocol status")
231+ if err == ErrNotInitSubProtocolChainStatus {
232+ startHash, err := c.store.GetMainChainHash(subProtocol.StartHeight())
233+ if err != nil {
234+ return errors.Wrap(err, subProtocol.Name(), "can't get block hash by height")
235+ }
236+
237+ if err := subProtocol.InitChainStatus(startHash); err != nil {
238+ return errors.Wrap(err, subProtocol.Name(), "fail init chain status")
239+ }
240+
241+ protocolHeight, protocolHash = subProtocol.StartHeight(), startHash
242+ } else if err != nil {
243+ return errors.Wrap(err, subProtocol.Name(), "can't get chain status")
226244 }
227245
228246 if *protocolHash == c.bestBlockHeader.Hash() {
--- a/protocol/vm/vmutil/script.go
+++ b/protocol/vm/vmutil/script.go
@@ -167,7 +167,7 @@ func P2WMCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
167167 // sellerKey: PublicKey) locks valueAmount of valueAsset {
168168 // clause partialTrade(exchangeAmount: Amount) {
169169 // define actualAmount: Integer = exchangeAmount * ratioDenominator / ratioNumerator
170-// verify actualAmount > 0 && actualAmount < valueAmount
170+// verify actualAmount >= 0 && actualAmount < valueAmount
171171 // define receiveAmount: Integer = exchangeAmount * 999 / 1000
172172 // lock receiveAmount of requestedAsset with sellerProgram
173173 // lock valueAmount-actualAmount of valueAsset with standardProgram
@@ -176,7 +176,7 @@ func P2WMCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
176176 // clause fullTrade() {
177177 // define requestedAmount: Integer = valueAmount * ratioNumerator / ratioDenominator
178178 // define requestedAmount: Integer = requestedAmount * 999 / 1000
179-// verify requestedAmount > 0
179+// verify requestedAmount >= 0
180180 // lock requestedAmount of requestedAsset with sellerProgram
181181 // unlock valueAmount of valueAsset
182182 // }
@@ -208,7 +208,7 @@ func P2WMCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
208208 // AMOUNT [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount]
209209 // OVER [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount]
210210 // 0 [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount 0]
211-// GREATERTHAN [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0)]
211+// GREATERTHANOREQUAL [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0)]
212212 // 2 [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) 2]
213213 // PICK [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) actualAmount]
214214 // 2 [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) actualAmount 2]
@@ -256,7 +256,7 @@ func P2WMCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
256256 // MULFRACTION [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
257257 // DUP [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount]
258258 // 0 [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount 0]
259-// GREATERTHAN [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount (requestedAmount > 0)]
259+// GREATERTHANOREQUAL [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount (requestedAmount > 0)]
260260 // VERIFY [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
261261 // FROMALTSTACK [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount <position>]
262262 // SWAP [... sellerKey standardProgram sellerProgram requestedAsset <position> requestedAmount]
@@ -311,7 +311,7 @@ func P2MCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
311311 builder.AddOp(vm.OP_AMOUNT)
312312 builder.AddOp(vm.OP_OVER)
313313 builder.AddOp(vm.OP_0)
314- builder.AddOp(vm.OP_GREATERTHAN)
314+ builder.AddOp(vm.OP_GREATERTHANOREQUAL)
315315 builder.AddOp(vm.OP_2)
316316 builder.AddOp(vm.OP_PICK)
317317 builder.AddOp(vm.OP_ROT)
@@ -356,7 +356,7 @@ func P2MCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
356356 builder.AddOp(vm.OP_MULFRACTION)
357357 builder.AddOp(vm.OP_DUP)
358358 builder.AddOp(vm.OP_0)
359- builder.AddOp(vm.OP_GREATERTHAN)
359+ builder.AddOp(vm.OP_GREATERTHANOREQUAL)
360360 builder.AddOp(vm.OP_VERIFY)
361361 builder.AddOp(vm.OP_FROMALTSTACK)
362362 builder.AddOp(vm.OP_SWAP)
--- a/test/rollback_test.go
+++ b/test/rollback_test.go
@@ -1460,7 +1460,7 @@ func TestRollback(t *testing.T) {
14601460 t.Fatal(err)
14611461 }
14621462
1463- chain, err := protocol.NewChain(store, nil, []protocol.Protocoler{movCore}, nil)
1463+ chain, err := protocol.NewChain(store, nil, []protocol.SubProtocol{movCore}, nil)
14641464 if err != nil {
14651465 t.Fatal(err)
14661466 }
--- /dev/null
+++ b/test/subprotocol_test.go
@@ -0,0 +1,235 @@
1+package test
2+
3+import (
4+ "os"
5+ "testing"
6+
7+ "github.com/bytom/vapor/application/mov"
8+ movDatabase "github.com/bytom/vapor/application/mov/database"
9+ "github.com/bytom/vapor/database"
10+ dbm "github.com/bytom/vapor/database/leveldb"
11+ "github.com/bytom/vapor/protocol"
12+ "github.com/bytom/vapor/protocol/bc"
13+ "github.com/bytom/vapor/protocol/bc/types"
14+ "github.com/bytom/vapor/protocol/state"
15+ "github.com/bytom/vapor/testutil"
16+)
17+
18+type chainStatus struct {
19+ blockHeight uint64
20+ blockHash bc.Hash
21+}
22+
23+type chainBlock struct {
24+ block *types.Block
25+ inMainChain bool
26+}
27+
28+var blocks = map[uint64][]*types.Block{
29+ 0: {
30+ {
31+ BlockHeader: types.BlockHeader{
32+ Height: 0,
33+ Timestamp: 1585814309,
34+ PreviousBlockHash: bc.Hash{},
35+ },
36+ },
37+ },
38+ 1: {
39+ // prev block is [0][0]
40+ {
41+ BlockHeader: types.BlockHeader{
42+ Height: 1,
43+ Timestamp: 1585814310,
44+ PreviousBlockHash: testutil.MustDecodeHash("2e5406c82fe34f6ee44fe694b05ffc8fb5918a026415b086df03fb03760b42a9"),
45+ },
46+ },
47+ // prev block is [0][0]
48+ {
49+ BlockHeader: types.BlockHeader{
50+ Height: 1,
51+ Timestamp: 1585814311,
52+ PreviousBlockHash: testutil.MustDecodeHash("2e5406c82fe34f6ee44fe694b05ffc8fb5918a026415b086df03fb03760b42a9"),
53+ },
54+ },
55+ },
56+ 2: {
57+ // prev block is [1][0]
58+ {
59+ BlockHeader: types.BlockHeader{
60+ Height: 2,
61+ Timestamp: 1585814320,
62+ PreviousBlockHash: testutil.MustDecodeHash("5bc198f4c0198e7e8b52173a82836cfd3f124d88bf052f53390948d845bf6fe0"),
63+ },
64+ },
65+ },
66+}
67+
68+func TestSyncProtocolStatus(t *testing.T) {
69+ cases := []struct {
70+ desc string
71+ savedBlocks []*chainBlock
72+ startHeight uint64
73+ startHash *bc.Hash
74+ wantChainStatus *chainStatus
75+ }{
76+ {
77+ desc: "start height from 0, mov is not init",
78+ savedBlocks: []*chainBlock{
79+ {
80+ block: blocks[0][0],
81+ inMainChain: true,
82+ },
83+ {
84+ block: blocks[1][0],
85+ inMainChain: true,
86+ },
87+ {
88+ block: blocks[2][0],
89+ inMainChain: true,
90+ },
91+ },
92+ startHeight: 0,
93+ wantChainStatus: &chainStatus{
94+ blockHeight: 2,
95+ blockHash: blocks[2][0].Hash(),
96+ },
97+ },
98+ {
99+ desc: "start height from 1, mov is not init",
100+ savedBlocks: []*chainBlock{
101+ {
102+ block: blocks[0][0],
103+ inMainChain: true,
104+ },
105+ {
106+ block: blocks[1][0],
107+ inMainChain: true,
108+ },
109+ {
110+ block: blocks[2][0],
111+ inMainChain: true,
112+ },
113+ },
114+ startHeight: 1,
115+ wantChainStatus: &chainStatus{
116+ blockHeight: 2,
117+ blockHash: blocks[2][0].Hash(),
118+ },
119+ },
120+ {
121+ desc: "start height from 1, state of mov is not sync completed",
122+ savedBlocks: []*chainBlock{
123+ {
124+ block: blocks[0][0],
125+ inMainChain: true,
126+ },
127+ {
128+ block: blocks[1][0],
129+ inMainChain: true,
130+ },
131+ {
132+ block: blocks[2][0],
133+ inMainChain: true,
134+ },
135+ },
136+ startHeight: 1,
137+ startHash: hashPtr(blocks[1][0].Hash()),
138+ wantChainStatus: &chainStatus{
139+ blockHeight: 2,
140+ blockHash: blocks[2][0].Hash(),
141+ },
142+ },
143+ {
144+ desc: "chain status of mov is forked",
145+ savedBlocks: []*chainBlock{
146+ {
147+ block: blocks[0][0],
148+ inMainChain: true,
149+ },
150+ {
151+ block: blocks[1][0],
152+ inMainChain: true,
153+ },
154+ {
155+ block: blocks[1][1],
156+ inMainChain: false,
157+ },
158+ {
159+ block: blocks[2][0],
160+ inMainChain: true,
161+ },
162+ },
163+ startHeight: 1,
164+ startHash: hashPtr(blocks[1][1].Hash()),
165+ wantChainStatus: &chainStatus{
166+ blockHeight: 2,
167+ blockHash: blocks[2][0].Hash(),
168+ },
169+ },
170+ }
171+
172+ defer os.RemoveAll("temp")
173+
174+ for i, c := range cases {
175+ chainDB := dbm.NewDB("core", "leveldb", "temp")
176+ store := database.NewStore(chainDB)
177+ if err := initStore(store, c.savedBlocks); err != nil {
178+ t.Fatal(err)
179+ }
180+
181+ movDB := dbm.NewDB("mov", "leveldb", "temp")
182+ movCore := mov.NewCoreWithDB(movDatabase.NewLevelDBMovStore(movDB), c.startHeight)
183+ if c.startHash != nil {
184+ if err := movCore.InitChainStatus(c.startHash); err != nil {
185+ t.Fatal(err)
186+ }
187+ }
188+
189+ _, err := protocol.NewChain(store, nil, []protocol.SubProtocol{movCore}, nil)
190+ if err != nil {
191+ t.Fatal(err)
192+ }
193+
194+ gotHeight, gotHash, err := movCore.ChainStatus()
195+ if err != nil {
196+ t.Fatal(err)
197+ }
198+
199+ if gotHeight != c.wantChainStatus.blockHeight || *gotHash != c.wantChainStatus.blockHash {
200+ t.Logf("#%d(%s): got chain status of sub protocol is not equals want chain status", i, c.desc)
201+ }
202+
203+ movDB.Close()
204+ chainDB.Close()
205+ os.RemoveAll("temp")
206+ }
207+}
208+
209+func initStore(store *database.Store, savedBlocks []*chainBlock) error {
210+ var mainBlockHeaders []*types.BlockHeader
211+ for _, block := range savedBlocks {
212+ if err := store.SaveBlock(block.block, bc.NewTransactionStatus()); err != nil {
213+ return err
214+ }
215+
216+ if block.inMainChain {
217+ mainBlockHeaders = append(mainBlockHeaders, &block.block.BlockHeader)
218+ }
219+
220+ last := len(mainBlockHeaders) - 1
221+ if err := store.SaveChainStatus(mainBlockHeaders[last], mainBlockHeaders[last], mainBlockHeaders, state.NewUtxoViewpoint(), nil); err != nil {
222+ return err
223+ }
224+ }
225+ return nil
226+}
227+
228+func hashPtr(hash bc.Hash) *bc.Hash {
229+ return &hash
230+}
231+
232+func TestBlockHash(t *testing.T) {
233+ blockHash := blocks[1][0].Hash()
234+ t.Log(blockHash.String())
235+}
--- a/version/version.go
+++ b/version/version.go
@@ -47,7 +47,7 @@ const (
4747
4848 var (
4949 // The full version string
50- Version = "1.1.0"
50+ Version = "1.1.4"
5151 // GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
5252 GitCommit string
5353 Status *UpdateStatus
Show on old repository browser