OSDN Git Service

add fast sync func (#204)
[bytom/vapor.git] / netsync / chainmgr / block_keeper_test.go
1 package chainmgr
2
3 import (
4         "encoding/json"
5         "testing"
6         "time"
7
8         "github.com/vapor/consensus"
9         "github.com/vapor/errors"
10         msgs "github.com/vapor/netsync/messages"
11         "github.com/vapor/protocol/bc"
12         "github.com/vapor/protocol/bc/types"
13         "github.com/vapor/testutil"
14 )
15
16 func TestRegularBlockSync(t *testing.T) {
17         baseChain := mockBlocks(nil, 50)
18         chainX := append(baseChain, mockBlocks(baseChain[50], 60)...)
19         chainY := append(baseChain, mockBlocks(baseChain[50], 70)...)
20         chainZ := append(baseChain, mockBlocks(baseChain[50], 200)...)
21
22         cases := []struct {
23                 syncTimeout time.Duration
24                 aBlocks     []*types.Block
25                 bBlocks     []*types.Block
26                 want        []*types.Block
27                 err         error
28         }{
29                 {
30                         syncTimeout: 30 * time.Second,
31                         aBlocks:     baseChain[:20],
32                         bBlocks:     baseChain[:50],
33                         want:        baseChain[:50],
34                         err:         nil,
35                 },
36                 {
37                         syncTimeout: 30 * time.Second,
38                         aBlocks:     chainX,
39                         bBlocks:     chainY,
40                         want:        chainY,
41                         err:         nil,
42                 },
43                 {
44                         syncTimeout: 30 * time.Second,
45                         aBlocks:     chainX[:52],
46                         bBlocks:     chainY[:53],
47                         want:        chainY[:53],
48                         err:         nil,
49                 },
50                 {
51                         syncTimeout: 30 * time.Second,
52                         aBlocks:     chainX[:52],
53                         bBlocks:     chainZ,
54                         want:        chainZ[:201],
55                         err:         nil,
56                 },
57         }
58
59         for i, c := range cases {
60                 syncTimeout = c.syncTimeout
61                 a := mockSync(c.aBlocks, nil)
62                 b := mockSync(c.bBlocks, nil)
63                 netWork := NewNetWork()
64                 netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
65                 netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
66                 if B2A, A2B, err := netWork.HandsShake(a, b); err != nil {
67                         t.Errorf("fail on peer hands shake %v", err)
68                 } else {
69                         go B2A.postMan()
70                         go A2B.postMan()
71                 }
72
73                 a.blockKeeper.syncPeer = a.peers.GetPeer("test node B")
74                 if err := a.blockKeeper.regularBlockSync(); errors.Root(err) != c.err {
75                         t.Errorf("case %d: got %v want %v", i, err, c.err)
76                 }
77
78                 got := []*types.Block{}
79                 for i := uint64(0); i <= a.chain.BestBlockHeight(); i++ {
80                         block, err := a.chain.GetBlockByHeight(i)
81                         if err != nil {
82                                 t.Errorf("case %d got err %v", i, err)
83                         }
84                         got = append(got, block)
85                 }
86
87                 if !testutil.DeepEqual(got, c.want) {
88                         t.Errorf("case %d: got %v want %v", i, got, c.want)
89                 }
90         }
91 }
92
93 func TestRequireBlock(t *testing.T) {
94         blocks := mockBlocks(nil, 5)
95         a := mockSync(blocks[:1], nil)
96         b := mockSync(blocks[:5], nil)
97         netWork := NewNetWork()
98         netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
99         netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
100         if B2A, A2B, err := netWork.HandsShake(a, b); err != nil {
101                 t.Errorf("fail on peer hands shake %v", err)
102         } else {
103                 go B2A.postMan()
104                 go A2B.postMan()
105         }
106
107         a.blockKeeper.syncPeer = a.peers.GetPeer("test node B")
108         b.blockKeeper.syncPeer = b.peers.GetPeer("test node A")
109         cases := []struct {
110                 syncTimeout   time.Duration
111                 testNode      *Manager
112                 requireHeight uint64
113                 want          *types.Block
114                 err           error
115         }{
116                 {
117                         syncTimeout:   30 * time.Second,
118                         testNode:      a,
119                         requireHeight: 4,
120                         want:          blocks[4],
121                         err:           nil,
122                 },
123                 {
124                         syncTimeout:   1 * time.Millisecond,
125                         testNode:      b,
126                         requireHeight: 4,
127                         want:          nil,
128                         err:           errRequestTimeout,
129                 },
130         }
131
132         for i, c := range cases {
133                 syncTimeout = c.syncTimeout
134                 got, err := c.testNode.blockKeeper.msgFetcher.requireBlock(c.testNode.blockKeeper.syncPeer.ID(), c.requireHeight)
135                 if !testutil.DeepEqual(got, c.want) {
136                         t.Errorf("case %d: got %v want %v", i, got, c.want)
137                 }
138                 if errors.Root(err) != c.err {
139                         t.Errorf("case %d: got %v want %v", i, err, c.err)
140                 }
141         }
142 }
143
144 func TestSendMerkleBlock(t *testing.T) {
145         cases := []struct {
146                 txCount        int
147                 relatedTxIndex []int
148         }{
149                 {
150                         txCount:        10,
151                         relatedTxIndex: []int{0, 2, 5},
152                 },
153                 {
154                         txCount:        0,
155                         relatedTxIndex: []int{},
156                 },
157                 {
158                         txCount:        10,
159                         relatedTxIndex: []int{},
160                 },
161                 {
162                         txCount:        5,
163                         relatedTxIndex: []int{0, 1, 2, 3, 4},
164                 },
165                 {
166                         txCount:        20,
167                         relatedTxIndex: []int{1, 6, 3, 9, 10, 19},
168                 },
169         }
170
171         for _, c := range cases {
172                 blocks := mockBlocks(nil, 2)
173                 targetBlock := blocks[1]
174                 txs, bcTxs := mockTxs(c.txCount)
175                 var err error
176
177                 targetBlock.Transactions = txs
178                 if targetBlock.TransactionsMerkleRoot, err = types.TxMerkleRoot(bcTxs); err != nil {
179                         t.Fatal(err)
180                 }
181
182                 spvNode := mockSync(blocks, nil)
183                 blockHash := targetBlock.Hash()
184                 var statusResult *bc.TransactionStatus
185                 if statusResult, err = spvNode.chain.GetTransactionStatus(&blockHash); err != nil {
186                         t.Fatal(err)
187                 }
188
189                 if targetBlock.TransactionStatusHash, err = types.TxStatusMerkleRoot(statusResult.VerifyStatus); err != nil {
190                         t.Fatal(err)
191                 }
192
193                 fullNode := mockSync(blocks, nil)
194                 netWork := NewNetWork()
195                 netWork.Register(spvNode, "192.168.0.1", "spv_node", consensus.SFFastSync)
196                 netWork.Register(fullNode, "192.168.0.2", "full_node", consensus.DefaultServices)
197
198                 var F2S *P2PPeer
199                 if F2S, _, err = netWork.HandsShake(spvNode, fullNode); err != nil {
200                         t.Errorf("fail on peer hands shake %v", err)
201                 }
202
203                 completed := make(chan error)
204                 go func() {
205                         msgBytes := <-F2S.msgCh
206                         _, msg, _ := decodeMessage(msgBytes)
207                         switch m := msg.(type) {
208                         case *msgs.MerkleBlockMessage:
209                                 var relatedTxIDs []*bc.Hash
210                                 for _, rawTx := range m.RawTxDatas {
211                                         tx := &types.Tx{}
212                                         if err := tx.UnmarshalText(rawTx); err != nil {
213                                                 completed <- err
214                                         }
215
216                                         relatedTxIDs = append(relatedTxIDs, &tx.ID)
217                                 }
218                                 var txHashes []*bc.Hash
219                                 for _, hashByte := range m.TxHashes {
220                                         hash := bc.NewHash(hashByte)
221                                         txHashes = append(txHashes, &hash)
222                                 }
223                                 if ok := types.ValidateTxMerkleTreeProof(txHashes, m.Flags, relatedTxIDs, targetBlock.TransactionsMerkleRoot); !ok {
224                                         completed <- errors.New("validate tx fail")
225                                 }
226
227                                 var statusHashes []*bc.Hash
228                                 for _, statusByte := range m.StatusHashes {
229                                         hash := bc.NewHash(statusByte)
230                                         statusHashes = append(statusHashes, &hash)
231                                 }
232                                 var relatedStatuses []*bc.TxVerifyResult
233                                 for _, statusByte := range m.RawTxStatuses {
234                                         status := &bc.TxVerifyResult{}
235                                         err := json.Unmarshal(statusByte, status)
236                                         if err != nil {
237                                                 completed <- err
238                                         }
239                                         relatedStatuses = append(relatedStatuses, status)
240                                 }
241                                 if ok := types.ValidateStatusMerkleTreeProof(statusHashes, m.Flags, relatedStatuses, targetBlock.TransactionStatusHash); !ok {
242                                         completed <- errors.New("validate status fail")
243                                 }
244
245                                 completed <- nil
246                         }
247                 }()
248
249                 spvPeer := fullNode.peers.GetPeer("spv_node")
250                 for i := 0; i < len(c.relatedTxIndex); i++ {
251                         spvPeer.AddFilterAddress(txs[c.relatedTxIndex[i]].Outputs[0].ControlProgram())
252                 }
253                 msg := &msgs.GetMerkleBlockMessage{RawHash: targetBlock.Hash().Byte32()}
254                 fullNode.handleGetMerkleBlockMsg(spvPeer, msg)
255                 if err := <-completed; err != nil {
256                         t.Fatal(err)
257                 }
258         }
259 }