OSDN Git Service

Merge pull request #4 from Bytom/develop
[bytom/bytom.git] / protocol / block_test.go
1 package protocol
2
3 import (
4         "context"
5         "encoding/hex"
6         "testing"
7         "time"
8
9         "github.com/bytom/protocol/bc"
10         "github.com/bytom/protocol/bc/legacy"
11         "github.com/bytom/protocol/prottest/memstore"
12         "github.com/bytom/protocol/state"
13         "github.com/bytom/testutil"
14 )
15
16 func TestGetBlock(t *testing.T) {
17         ctx := context.Background()
18
19         b1 := &legacy.Block{BlockHeader: legacy.BlockHeader{Height: 1}}
20         noBlocks := memstore.New()
21         oneBlock := memstore.New()
22         oneBlock.SaveBlock(ctx, b1)
23         oneBlock.SaveSnapshot(ctx, 1, state.Empty())
24
25         cases := []struct {
26                 store   Store
27                 want    *legacy.Block
28                 wantErr bool
29         }{
30                 {noBlocks, nil, true},
31                 {oneBlock, b1, false},
32         }
33
34         for _, test := range cases {
35                 c, err := NewChain(ctx, b1.Hash(), test.store, nil)
36                 if err != nil {
37                         testutil.FatalErr(t, err)
38                 }
39                 got, gotErr := c.GetBlock(ctx, c.Height())
40                 if !testutil.DeepEqual(got, test.want) {
41                         t.Errorf("got latest = %+v want %+v", got, test.want)
42                 }
43                 if (gotErr != nil) != test.wantErr {
44                         t.Errorf("got latest err = %q want err?: %t", gotErr, test.wantErr)
45                 }
46         }
47 }
48
49 func TestNoTimeTravel(t *testing.T) {
50         ctx := context.Background()
51         c, err := NewChain(ctx, bc.Hash{}, memstore.New(), nil)
52         if err != nil {
53                 t.Fatal(err)
54         }
55
56         c.setHeight(1)
57         c.setHeight(2)
58
59         c.setHeight(1) // don't go backward
60         if c.state.height != 2 {
61                 t.Fatalf("c.state.height = %d want 2", c.state.height)
62         }
63 }
64
65 func TestWaitForBlockSoonAlreadyExists(t *testing.T) {
66         c, _ := newTestChain(t, time.Now())
67         makeEmptyBlock(t, c) // height=2
68         makeEmptyBlock(t, c) // height=3
69
70         err := <-c.BlockSoonWaiter(context.Background(), 2)
71         if err != nil {
72                 t.Fatal(err)
73         }
74 }
75
76 func TestWaitForBlockSoonDistantFuture(t *testing.T) {
77         c, _ := newTestChain(t, time.Now())
78
79         got := <-c.BlockSoonWaiter(context.Background(), 100) // distant future
80         want := ErrTheDistantFuture
81         if got != want {
82                 t.Errorf("BlockSoonWaiter(100) = %+v want %+v", got, want)
83         }
84 }
85
86 func TestWaitForBlockSoonWaits(t *testing.T) {
87         // This test is inherently racy. It's possible
88         // that the block creation might run before
89         // the wait's internal test loop finds no block.
90         // In that case, the test will pass, but it will
91         // not have tested anything.
92         //
93         // It's the best we can do.
94
95         c, _ := newTestChain(t, time.Now())
96         makeEmptyBlock(t, c) // height=2
97
98         go func() {
99                 time.Sleep(10 * time.Millisecond) // sorry for the slow test 
100                 makeEmptyBlock(t, c)              // height=3
101         }()
102
103         err := <-c.BlockSoonWaiter(context.Background(), 3)
104         if err != nil {
105                 t.Fatal(err)
106         }
107         if g := c.Height(); g != 3 {
108                 t.Errorf("height after waiting = %d want 3", g)
109         }
110 }
111
112 func TestWaitForBlockSoonTimesout(t *testing.T) {
113         c, _ := newTestChain(t, time.Now())
114         go func() {
115                 makeEmptyBlock(t, c) // height=2
116         }()
117
118         ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
119         defer cancel()
120
121         err := <-c.BlockSoonWaiter(ctx, 3)
122         if err != ctx.Err() {
123                 t.Fatalf("expected timeout err, got %v", err)
124         }
125 }
126
127 func TestGenerateBlock(t *testing.T) {
128         ctx := context.Background()
129         now := time.Unix(233400000, 0)
130         c, b1 := newTestChain(t, now)
131
132         initialBlockHash := b1.Hash()
133         assetID := bc.ComputeAssetID(nil, &initialBlockHash, 1, &bc.EmptyStringHash)
134
135         txs := []*legacy.Tx{
136                 legacy.NewTx(legacy.TxData{
137                         Version: 1,
138                         MinTime: 233400000000,
139                         MaxTime: 233400000001,
140                         Inputs: []*legacy.TxInput{
141                                 legacy.NewIssuanceInput([]byte{1}, 50, nil, initialBlockHash, nil, [][]byte{
142                                         nil,
143                                         mustDecodeHex("30450221009037e1d39b7d59d24eba8012baddd5f4ab886a51b46f52b7c479ddfa55eeb5c5022076008409243475b25dfba6db85e15cf3d74561a147375941e4830baa69769b5101"),
144                                         mustDecodeHex("51210210b002870438af79b829bc22c4505e14779ef0080c411ad497d7a0846ee0af6f51ae")}, nil),
145                         },
146                         Outputs: []*legacy.TxOutput{
147                                 legacy.NewTxOutput(assetID, 50, mustDecodeHex("a9145881cd104f8d64635751ac0f3c0decf9150c110687"), nil),
148                         },
149                 }),
150                 legacy.NewTx(legacy.TxData{
151                         Version: 1,
152                         MinTime: 233400000000,
153                         MaxTime: 233400000001,
154                         Inputs: []*legacy.TxInput{
155                                 legacy.NewIssuanceInput([]byte{2}, 50, nil, initialBlockHash, nil, [][]byte{
156                                         nil,
157                                         mustDecodeHex("3045022100f3bcffcfd6a1ce9542b653500386cd0ee7b9c86c59390ca0fc0238c0ebe3f1d6022065ac468a51a016842660c3a616c99a9aa5109a3bad1877ba3e0f010f3972472e01"),
158                                         mustDecodeHex("51210210b002870438af79b829bc22c4505e14779ef0080c411ad497d7a0846ee0af6f51ae"),
159                                 }, nil),
160                         },
161                         Outputs: []*legacy.TxOutput{
162                                 legacy.NewTxOutput(assetID, 50, mustDecodeHex("a914c171e443e05b953baa7b7d834028ed91e47b4d0b87"), nil),
163                         },
164                 }),
165         }
166
167         got, _, err := c.GenerateBlock(ctx, b1, state.Empty(), now, txs)
168         if err != nil {
169                 t.Fatalf("err got = %v want nil", err)
170         }
171
172         // TODO(bobg): verify these hashes are correct
173         wantTxRoot := mustDecodeHash("ab5f5f111beb1e6b49da8334360589c7da3aac1cdd61067ea9a55bec47cb745c")
174         wantAssetsRoot := mustDecodeHash("a31a9b5f71a6d6fa0c87361db4a98c9a82f603f9d9ff584f6613b9d56ccf5ebd")
175
176         want := &legacy.Block{
177                 BlockHeader: legacy.BlockHeader{
178                         Version:           1,
179                         Height:            2,
180                         PreviousBlockHash: b1.Hash(),
181                         TimestampMS:       bc.Millis(now),
182                         BlockCommitment: legacy.BlockCommitment{
183                                 TransactionsMerkleRoot: wantTxRoot,
184                                 AssetsMerkleRoot:       wantAssetsRoot,
185                                 ConsensusProgram:       b1.ConsensusProgram,
186                         },
187                 },
188                 Transactions: txs,
189         }
190
191         if !testutil.DeepEqual(got, want) {
192                 t.Errorf("generated block:\ngot:  %+v\nwant: %+v", got, want)
193         }
194 }
195
196 func TestValidateBlockForSig(t *testing.T) {
197         initialBlock, err := NewInitialBlock(testutil.TestPubs, 1, time.Now())
198         if err != nil {
199                 t.Fatal("unexpected error ", err)
200         }
201
202         ctx := context.Background()
203         c, err := NewChain(ctx, initialBlock.Hash(), memstore.New(), nil)
204         if err != nil {
205                 t.Fatal("unexpected error ", err)
206         }
207
208         err = c.ValidateBlockForSig(ctx, initialBlock)
209         if err != nil {
210                 t.Error("unexpected error ", err)
211         }
212 }
213
214 // newTestChain returns a new Chain using memstore for storage,
215 // along with an initial block b1 (with a 0/0 multisig program).
216 // It commits b1 before returning.
217 func newTestChain(tb testing.TB, ts time.Time) (c *Chain, b1 *legacy.Block) {
218         ctx := context.Background()
219
220         var err error
221
222         b1, err = NewInitialBlock(nil, 0, ts)
223         if err != nil {
224                 testutil.FatalErr(tb, err)
225         }
226         c, err = NewChain(ctx, b1.Hash(), memstore.New(), nil)
227         if err != nil {
228                 testutil.FatalErr(tb, err)
229         }
230         // TODO(tessr): consider adding MaxIssuanceWindow to NewChain
231         c.MaxIssuanceWindow = 48 * time.Hour
232         err = c.CommitAppliedBlock(ctx, b1, state.Empty())
233         if err != nil {
234                 testutil.FatalErr(tb, err)
235         }
236         return c, b1
237 }
238
239 func makeEmptyBlock(tb testing.TB, c *Chain) {
240         ctx := context.Background()
241
242         curBlock, err := c.GetBlock(ctx, c.Height())
243         if err != nil {
244                 testutil.FatalErr(tb, err)
245         }
246
247         if len(curBlock.Transactions) > 0 {
248                 tb.Fatal("cannot make nonempty block")
249         }
250
251         curState := state.Empty()
252
253         nextBlock, nextState, err := c.GenerateBlock(ctx, curBlock, curState, time.Now(), nil)
254         if err != nil {
255                 testutil.FatalErr(tb, err)
256         }
257         err = c.CommitAppliedBlock(ctx, nextBlock, nextState)
258         if err != nil {
259                 testutil.FatalErr(tb, err)
260         }
261 }
262
263 func mustDecodeHex(s string) []byte {
264         data, err := hex.DecodeString(s)
265         if err != nil {
266                 panic(err)
267         }
268         return data
269 }
270
271 func mustDecodeHash(s string) (h bc.Hash) {
272         err := h.UnmarshalText([]byte(s))
273         if err != nil {
274                 panic(err)
275         }
276         return h
277 }