OSDN Git Service

b5b60c08e978bd7b1dd205d8de6097c663d52fd3
[bytom/bytom-spv.git] / protocol / validation / validation.go
1 package validation
2
3 import (
4         "fmt"
5         "sort"
6         "time"
7
8         "github.com/bytom/common"
9         "github.com/bytom/consensus"
10         "github.com/bytom/consensus/difficulty"
11         "github.com/bytom/consensus/segwit"
12         "github.com/bytom/database"
13         "github.com/bytom/errors"
14         "github.com/bytom/math/checked"
15         "github.com/bytom/protocol/bc"
16         "github.com/bytom/protocol/vm"
17 )
18
19 const (
20         muxGasCost = int64(10)
21         // timeRangeGash is the block height we will reach after 100 years
22         timeRangeGash = uint64(21024000)
23 )
24
25 // GasState record the gas usage status
26 type GasState struct {
27         BTMValue   uint64
28         GasLeft    int64
29         GasUsed    int64
30         GasVaild   bool
31         storageGas int64
32 }
33
34 func (g *GasState) setGas(BTMValue int64, txSize int64) error {
35         if BTMValue < 0 {
36                 return errors.Wrap(errGasCalculate, "input BTM is negative")
37         }
38
39         g.BTMValue = uint64(BTMValue)
40
41         if BTMValue == 0 {
42                 g.GasLeft = muxGasCost
43                 return nil
44         }
45
46         var ok bool
47         if g.GasLeft, ok = checked.DivInt64(BTMValue, consensus.VMGasRate); !ok {
48                 return errors.Wrap(errGasCalculate, "setGas calc gas amount")
49         }
50
51         if g.GasLeft > consensus.MaxGasAmount {
52                 g.GasLeft = consensus.MaxGasAmount
53         }
54
55         if g.storageGas, ok = checked.MulInt64(txSize, consensus.StorageGasRate); !ok {
56                 return errors.Wrap(errGasCalculate, "setGas calc tx storage gas")
57         }
58         return nil
59 }
60
61 func (g *GasState) setGasVaild() error {
62         var ok bool
63         if g.GasLeft, ok = checked.SubInt64(g.GasLeft, g.storageGas); !ok || g.GasLeft < 0 {
64                 return errors.Wrap(errGasCalculate, "setGasVaild calc gasLeft")
65         }
66
67         if g.GasUsed, ok = checked.AddInt64(g.GasUsed, g.storageGas); !ok {
68                 return errors.Wrap(errGasCalculate, "setGasVaild calc gasUsed")
69         }
70
71         g.GasVaild = true
72         return nil
73 }
74
75 func (g *GasState) updateUsage(gasLeft int64) error {
76         if gasLeft < 0 {
77                 return errors.Wrap(errGasCalculate, "updateUsage input negative gas")
78         }
79
80         if gasUsed, ok := checked.SubInt64(g.GasLeft, gasLeft); ok {
81                 g.GasUsed += gasUsed
82                 g.GasLeft = gasLeft
83         } else {
84                 return errors.Wrap(errGasCalculate, "updateUsage calc gas diff")
85         }
86
87         if !g.GasVaild && (g.GasUsed > consensus.DefaultGasCredit || g.storageGas > g.GasLeft) {
88                 return errOverGasCredit
89         }
90         return nil
91 }
92
93 // validationState contains the context that must propagate through
94 // the transaction graph when validating entries.
95 type validationState struct {
96         // The ID of the blockchain
97         block *bc.Block
98
99         // The enclosing transaction object
100         tx *bc.Tx
101
102         // The ID of the nearest enclosing entry
103         entryID bc.Hash
104
105         // The source position, for validating ValueSources
106         sourcePos uint64
107
108         // The destination position, for validating ValueDestinations
109         destPos uint64
110
111         // Memoized per-entry validation results
112         cache map[bc.Hash]error
113
114         gasStatus *GasState
115 }
116
117 var (
118         errBadTimestamp             = errors.New("block timestamp is not in the vaild range")
119         errBadBits                  = errors.New("block bits is invaild")
120         errGasCalculate             = errors.New("gas usage calculate got a math error")
121         errEmptyResults             = errors.New("transaction has no results")
122         errMismatchedAssetID        = errors.New("mismatched asset id")
123         errMismatchedBlock          = errors.New("mismatched block")
124         errMismatchedMerkleRoot     = errors.New("mismatched merkle root")
125         errMismatchedPosition       = errors.New("mismatched value source/dest positions")
126         errMismatchedReference      = errors.New("mismatched reference")
127         errMismatchedTxStatus       = errors.New("mismatched transaction status")
128         errMismatchedValue          = errors.New("mismatched value")
129         errMisorderedBlockHeight    = errors.New("misordered block height")
130         errMisorderedBlockTime      = errors.New("misordered block time")
131         errMissingField             = errors.New("missing required field")
132         errNoGas                    = errors.New("no gas input")
133         errNoPrevBlock              = errors.New("no previous block")
134         errNoSource                 = errors.New("no source for value")
135         errNonemptyExtHash          = errors.New("non-empty extension hash")
136         errOverflow                 = errors.New("arithmetic overflow/underflow")
137         errOverGasCredit            = errors.New("all gas credit has been spend")
138         errOverBlockLimit           = errors.New("block's gas is over the limit")
139         errPosition                 = errors.New("invalid source or destination position")
140         errWorkProof                = errors.New("invalid difficulty proof of work")
141         errTxVersion                = errors.New("invalid transaction version")
142         errUnbalanced               = errors.New("unbalanced")
143         errUntimelyTransaction      = errors.New("block timestamp outside transaction time range")
144         errVersionRegression        = errors.New("version regression")
145         errWrongBlockSize           = errors.New("block size is too big")
146         errWrongTransactionSize     = errors.New("transaction size is not in vaild range")
147         errWrongTransactionStatus   = errors.New("transaction status is wrong")
148         errWrongCoinbaseTransaction = errors.New("wrong coinbase transaction")
149         errWrongCoinbaseAsset       = errors.New("wrong coinbase asset id")
150         errNotStandardTx            = errors.New("gas transaction is not standard transaction")
151 )
152
153 func checkValid(vs *validationState, e bc.Entry) (err error) {
154         entryID := bc.EntryID(e)
155         var ok bool
156         if err, ok = vs.cache[entryID]; ok {
157                 return err
158         }
159
160         defer func() {
161                 vs.cache[entryID] = err
162         }()
163
164         switch e := e.(type) {
165         case *bc.TxHeader:
166
167                 for i, resID := range e.ResultIds {
168                         resultEntry := vs.tx.Entries[*resID]
169                         vs2 := *vs
170                         vs2.entryID = *resID
171                         err = checkValid(&vs2, resultEntry)
172                         if err != nil {
173                                 return errors.Wrapf(err, "checking result %d", i)
174                         }
175                 }
176
177                 if e.Version == 1 {
178                         if len(e.ResultIds) == 0 {
179                                 return errEmptyResults
180                         }
181
182                         if e.ExtHash != nil && !e.ExtHash.IsZero() {
183                                 return errNonemptyExtHash
184                         }
185                 }
186
187         case *bc.Coinbase:
188                 if vs.block == nil || len(vs.block.Transactions) == 0 || vs.block.Transactions[0] != vs.tx {
189                         return errWrongCoinbaseTransaction
190                 }
191
192                 if *e.WitnessDestination.Value.AssetId != *consensus.BTMAssetID {
193                         return errWrongCoinbaseAsset
194                 }
195
196                 vs2 := *vs
197                 vs2.destPos = 0
198                 err = checkValidDest(&vs2, e.WitnessDestination)
199                 if err != nil {
200                         return errors.Wrap(err, "checking coinbase destination")
201                 }
202
203         case *bc.Mux:
204                 parity := make(map[bc.AssetID]int64)
205                 for i, src := range e.Sources {
206                         sum, ok := checked.AddInt64(parity[*src.Value.AssetId], int64(src.Value.Amount))
207                         if !ok {
208                                 return errors.WithDetailf(errOverflow, "adding %d units of asset %x from mux source %d to total %d overflows int64", src.Value.Amount, src.Value.AssetId.Bytes(), i, parity[*src.Value.AssetId])
209                         }
210                         parity[*src.Value.AssetId] = sum
211                 }
212
213                 for i, dest := range e.WitnessDestinations {
214                         sum, ok := parity[*dest.Value.AssetId]
215                         if !ok {
216                                 return errors.WithDetailf(errNoSource, "mux destination %d, asset %x, has no corresponding source", i, dest.Value.AssetId.Bytes())
217                         }
218
219                         diff, ok := checked.SubInt64(sum, int64(dest.Value.Amount))
220                         if !ok {
221                                 return errors.WithDetailf(errOverflow, "subtracting %d units of asset %x from mux destination %d from total %d underflows int64", dest.Value.Amount, dest.Value.AssetId.Bytes(), i, sum)
222                         }
223                         parity[*dest.Value.AssetId] = diff
224                 }
225
226                 for assetID, amount := range parity {
227                         if assetID == *consensus.BTMAssetID {
228                                 if err = vs.gasStatus.setGas(amount, int64(vs.tx.SerializedSize)); err != nil {
229                                         return err
230                                 }
231                         } else if amount != 0 {
232                                 return errors.WithDetailf(errUnbalanced, "asset %x sources - destinations = %d (should be 0)", assetID.Bytes(), amount)
233                         }
234                 }
235
236                 gasLeft, err := vm.Verify(NewTxVMContext(vs, e, e.Program, e.WitnessArguments), vs.gasStatus.GasLeft)
237                 if err != nil {
238                         return errors.Wrap(err, "checking mux program")
239                 }
240                 if err = vs.gasStatus.updateUsage(gasLeft); err != nil {
241                         return err
242                 }
243
244                 for _, BTMInputID := range vs.tx.GasInputIDs {
245                         e, ok := vs.tx.Entries[BTMInputID]
246                         if !ok {
247                                 return errors.Wrapf(bc.ErrMissingEntry, "entry for bytom input %x not found", BTMInputID)
248                         }
249
250                         vs2 := *vs
251                         vs2.entryID = BTMInputID
252                         if err := checkValid(&vs2, e); err != nil {
253                                 return errors.Wrap(err, "checking value source")
254                         }
255                 }
256
257                 for i, dest := range e.WitnessDestinations {
258                         vs2 := *vs
259                         vs2.destPos = uint64(i)
260                         err = checkValidDest(&vs2, dest)
261                         if err != nil {
262                                 return errors.Wrapf(err, "checking mux destination %d", i)
263                         }
264                 }
265
266                 if vs.tx.Version == 1 && e.ExtHash != nil && !e.ExtHash.IsZero() {
267                         return errNonemptyExtHash
268                 }
269
270                 if err := vs.gasStatus.setGasVaild(); err != nil {
271                         return err
272                 }
273
274                 for i, src := range e.Sources {
275                         vs2 := *vs
276                         vs2.sourcePos = uint64(i)
277                         err = checkValidSrc(&vs2, src)
278                         if err != nil {
279                                 return errors.Wrapf(err, "checking mux source %d", i)
280                         }
281                 }
282
283         case *bc.Nonce:
284                 //TODO: add block heigh range check on the control program
285                 gasLeft, err := vm.Verify(NewTxVMContext(vs, e, e.Program, e.WitnessArguments), vs.gasStatus.GasLeft)
286                 if err != nil {
287                         return errors.Wrap(err, "checking nonce program")
288                 }
289                 if err = vs.gasStatus.updateUsage(gasLeft); err != nil {
290                         return err
291                 }
292
293                 if vs.tx.Version == 1 && e.ExtHash != nil && !e.ExtHash.IsZero() {
294                         return errNonemptyExtHash
295                 }
296
297         case *bc.Output:
298                 vs2 := *vs
299                 vs2.sourcePos = 0
300                 err = checkValidSrc(&vs2, e.Source)
301                 if err != nil {
302                         return errors.Wrap(err, "checking output source")
303                 }
304
305                 if vs.tx.Version == 1 && e.ExtHash != nil && !e.ExtHash.IsZero() {
306                         return errNonemptyExtHash
307                 }
308
309         case *bc.Retirement:
310                 vs2 := *vs
311                 vs2.sourcePos = 0
312                 err = checkValidSrc(&vs2, e.Source)
313                 if err != nil {
314                         return errors.Wrap(err, "checking retirement source")
315                 }
316
317                 if vs.tx.Version == 1 && e.ExtHash != nil && !e.ExtHash.IsZero() {
318                         return errNonemptyExtHash
319                 }
320
321         case *bc.Issuance:
322                 computedAssetID := e.WitnessAssetDefinition.ComputeAssetID()
323                 if computedAssetID != *e.Value.AssetId {
324                         return errors.WithDetailf(errMismatchedAssetID, "asset ID is %x, issuance wants %x", computedAssetID.Bytes(), e.Value.AssetId.Bytes())
325                 }
326
327                 anchor, ok := vs.tx.Entries[*e.AnchorId]
328                 if !ok {
329                         return errors.Wrapf(bc.ErrMissingEntry, "entry for issuance anchor %x not found", e.AnchorId.Bytes())
330                 }
331
332                 gasLeft, err := vm.Verify(NewTxVMContext(vs, e, e.WitnessAssetDefinition.IssuanceProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
333                 if err != nil {
334                         return errors.Wrap(err, "checking issuance program")
335                 }
336                 if err = vs.gasStatus.updateUsage(gasLeft); err != nil {
337                         return err
338                 }
339
340                 var anchored *bc.Hash
341                 switch a := anchor.(type) {
342                 case *bc.Nonce:
343                         anchored = a.WitnessAnchoredId
344
345                 case *bc.Spend:
346                         anchored = a.WitnessAnchoredId
347
348                 case *bc.Issuance:
349                         anchored = a.WitnessAnchoredId
350
351                 default:
352                         return errors.WithDetailf(bc.ErrEntryType, "issuance anchor has type %T, should be nonce, spend, or issuance", anchor)
353                 }
354
355                 if *anchored != vs.entryID {
356                         return errors.WithDetailf(errMismatchedReference, "issuance %x anchor is for %x", vs.entryID.Bytes(), anchored.Bytes())
357                 }
358
359                 anchorVS := *vs
360                 anchorVS.entryID = *e.AnchorId
361                 err = checkValid(&anchorVS, anchor)
362                 if err != nil {
363                         return errors.Wrap(err, "checking issuance anchor")
364                 }
365
366                 destVS := *vs
367                 destVS.destPos = 0
368                 err = checkValidDest(&destVS, e.WitnessDestination)
369                 if err != nil {
370                         return errors.Wrap(err, "checking issuance destination")
371                 }
372
373                 if vs.tx.Version == 1 && e.ExtHash != nil && !e.ExtHash.IsZero() {
374                         return errNonemptyExtHash
375                 }
376
377         case *bc.Spend:
378                 if e.SpentOutputId == nil {
379                         return errors.Wrap(errMissingField, "spend without spent output ID")
380                 }
381                 spentOutput, err := vs.tx.Output(*e.SpentOutputId)
382                 if err != nil {
383                         return errors.Wrap(err, "getting spend prevout")
384                 }
385                 gasLeft, err := vm.Verify(NewTxVMContext(vs, e, spentOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
386                 if err != nil {
387                         return errors.Wrap(err, "checking control program")
388                 }
389                 if err = vs.gasStatus.updateUsage(gasLeft); err != nil {
390                         return err
391                 }
392
393                 eq, err := spentOutput.Source.Value.Equal(e.WitnessDestination.Value)
394                 if err != nil {
395                         return err
396                 }
397                 if !eq {
398                         return errors.WithDetailf(
399                                 errMismatchedValue,
400                                 "previous output is for %d unit(s) of %x, spend wants %d unit(s) of %x",
401                                 spentOutput.Source.Value.Amount,
402                                 spentOutput.Source.Value.AssetId.Bytes(),
403                                 e.WitnessDestination.Value.Amount,
404                                 e.WitnessDestination.Value.AssetId.Bytes(),
405                         )
406                 }
407
408                 vs2 := *vs
409                 vs2.destPos = 0
410                 err = checkValidDest(&vs2, e.WitnessDestination)
411                 if err != nil {
412                         return errors.Wrap(err, "checking spend destination")
413                 }
414
415                 if vs.tx.Version == 1 && e.ExtHash != nil && !e.ExtHash.IsZero() {
416                         return errNonemptyExtHash
417                 }
418
419         default:
420                 return fmt.Errorf("entry has unexpected type %T", e)
421         }
422
423         return nil
424 }
425
426 func checkValidSrc(vstate *validationState, vs *bc.ValueSource) error {
427         if vs == nil {
428                 return errors.Wrap(errMissingField, "empty value source")
429         }
430         if vs.Ref == nil {
431                 return errors.Wrap(errMissingField, "missing ref on value source")
432         }
433         if vs.Value == nil || vs.Value.AssetId == nil {
434                 return errors.Wrap(errMissingField, "missing value on value source")
435         }
436
437         e, ok := vstate.tx.Entries[*vs.Ref]
438         if !ok {
439                 return errors.Wrapf(bc.ErrMissingEntry, "entry for value source %x not found", vs.Ref.Bytes())
440         }
441         vstate2 := *vstate
442         vstate2.entryID = *vs.Ref
443         err := checkValid(&vstate2, e)
444         if err != nil {
445                 return errors.Wrap(err, "checking value source")
446         }
447
448         var dest *bc.ValueDestination
449         switch ref := e.(type) {
450         case *bc.Coinbase:
451                 if vs.Position != 0 {
452                         return errors.Wrapf(errPosition, "invalid position %d for coinbase source", vs.Position)
453                 }
454                 dest = ref.WitnessDestination
455         case *bc.Issuance:
456                 if vs.Position != 0 {
457                         return errors.Wrapf(errPosition, "invalid position %d for issuance source", vs.Position)
458                 }
459                 dest = ref.WitnessDestination
460
461         case *bc.Spend:
462                 if vs.Position != 0 {
463                         return errors.Wrapf(errPosition, "invalid position %d for spend source", vs.Position)
464                 }
465                 dest = ref.WitnessDestination
466
467         case *bc.Mux:
468                 if vs.Position >= uint64(len(ref.WitnessDestinations)) {
469                         return errors.Wrapf(errPosition, "invalid position %d for %d-destination mux source", vs.Position, len(ref.WitnessDestinations))
470                 }
471                 dest = ref.WitnessDestinations[vs.Position]
472
473         default:
474                 return errors.Wrapf(bc.ErrEntryType, "value source is %T, should be coinbase, issuance, spend, or mux", e)
475         }
476
477         if dest.Ref == nil || *dest.Ref != vstate.entryID {
478                 return errors.Wrapf(errMismatchedReference, "value source for %x has disagreeing destination %x", vstate.entryID.Bytes(), dest.Ref.Bytes())
479         }
480
481         if dest.Position != vstate.sourcePos {
482                 return errors.Wrapf(errMismatchedPosition, "value source position %d disagrees with %d", dest.Position, vstate.sourcePos)
483         }
484
485         eq, err := dest.Value.Equal(vs.Value)
486         if err != nil {
487                 return errors.Sub(errMissingField, err)
488         }
489         if !eq {
490                 return errors.Wrapf(errMismatchedValue, "source value %v disagrees with %v", dest.Value, vs.Value)
491         }
492
493         return nil
494 }
495
496 func checkValidDest(vs *validationState, vd *bc.ValueDestination) error {
497         if vd == nil {
498                 return errors.Wrap(errMissingField, "empty value destination")
499         }
500         if vd.Ref == nil {
501                 return errors.Wrap(errMissingField, "missing ref on value destination")
502         }
503         if vd.Value == nil || vd.Value.AssetId == nil {
504                 return errors.Wrap(errMissingField, "missing value on value source")
505         }
506
507         e, ok := vs.tx.Entries[*vd.Ref]
508         if !ok {
509                 return errors.Wrapf(bc.ErrMissingEntry, "entry for value destination %x not found", vd.Ref.Bytes())
510         }
511         var src *bc.ValueSource
512         switch ref := e.(type) {
513         case *bc.Output:
514                 if vd.Position != 0 {
515                         return errors.Wrapf(errPosition, "invalid position %d for output destination", vd.Position)
516                 }
517                 src = ref.Source
518
519         case *bc.Retirement:
520                 if vd.Position != 0 {
521                         return errors.Wrapf(errPosition, "invalid position %d for retirement destination", vd.Position)
522                 }
523                 src = ref.Source
524
525         case *bc.Mux:
526                 if vd.Position >= uint64(len(ref.Sources)) {
527                         return errors.Wrapf(errPosition, "invalid position %d for %d-source mux destination", vd.Position, len(ref.Sources))
528                 }
529                 src = ref.Sources[vd.Position]
530
531         default:
532                 return errors.Wrapf(bc.ErrEntryType, "value destination is %T, should be output, retirement, or mux", e)
533         }
534
535         if src.Ref == nil || *src.Ref != vs.entryID {
536                 return errors.Wrapf(errMismatchedReference, "value destination for %x has disagreeing source %x", vs.entryID.Bytes(), src.Ref.Bytes())
537         }
538
539         if src.Position != vs.destPos {
540                 return errors.Wrapf(errMismatchedPosition, "value destination position %d disagrees with %d", src.Position, vs.destPos)
541         }
542
543         eq, err := src.Value.Equal(vd.Value)
544         if err != nil {
545                 return errors.Sub(errMissingField, err)
546         }
547         if !eq {
548                 return errors.Wrapf(errMismatchedValue, "destination value %v disagrees with %v", src.Value, vd.Value)
549         }
550
551         return nil
552 }
553
554 // ValidateBlock validates a block and the transactions within.
555 // It does not run the consensus program; for that, see ValidateBlockSig.
556 func ValidateBlock(b, prev *bc.Block, seed *bc.Hash, store database.Store) error {
557         if b.Height > 0 {
558                 if prev == nil {
559                         return errors.WithDetailf(errNoPrevBlock, "height %d", b.Height)
560                 }
561                 if err := validateBlockAgainstPrev(b, prev); err != nil {
562                         return err
563                 }
564                 if err := validateBlockTime(b, store); err != nil {
565                         return err
566                 }
567                 if err := validateBlockBits(b, prev, store); err != nil {
568                         return err
569                 }
570         }
571
572         if !difficulty.CheckProofOfWork(&b.ID, seed, b.BlockHeader.Bits) {
573                 return errWorkProof
574         }
575
576         b.TransactionStatus = bc.NewTransactionStatus()
577         coinbaseValue := consensus.BlockSubsidy(b.BlockHeader.Height)
578         gasUsed := uint64(0)
579         for i, tx := range b.Transactions {
580                 gasStatus, err := ValidateTx(tx, b)
581                 gasOnlyTx := false
582                 if err != nil {
583                         if gasStatus == nil || !gasStatus.GasVaild {
584                                 return errors.Wrapf(err, "validity of transaction %d of %d", i, len(b.Transactions))
585                         }
586                         gasOnlyTx = true
587                 }
588                 b.TransactionStatus.SetStatus(i, gasOnlyTx)
589                 coinbaseValue += gasStatus.BTMValue
590                 gasUsed += uint64(gasStatus.GasUsed)
591         }
592
593         if gasUsed > consensus.MaxBlockGas {
594                 return errOverBlockLimit
595         }
596
597         // check the coinbase output entry value
598         if err := validateCoinbase(b.Transactions[0], coinbaseValue); err != nil {
599                 return err
600         }
601
602         txRoot, err := bc.TxMerkleRoot(b.Transactions)
603         if err != nil {
604                 return errors.Wrap(err, "computing transaction merkle root")
605         }
606
607         if txRoot != *b.TransactionsRoot {
608                 return errors.WithDetailf(errMismatchedMerkleRoot, "computed %x, current block wants %x", txRoot.Bytes(), b.TransactionsRoot.Bytes())
609         }
610
611         txStatusHash, err := bc.TxStatusMerkleRoot(b.TransactionStatus.VerifyStatus)
612         if err != nil {
613                 return err
614         }
615
616         if txStatusHash != *b.TransactionStatusHash {
617                 return errMismatchedTxStatus
618         }
619         return nil
620 }
621
622 func validateBlockBits(b, prev *bc.Block, store database.Store) error {
623         if prev.Height%consensus.BlocksPerRetarget != 0 || prev.Height == 0 {
624                 if b.Bits != prev.Bits {
625                         return errBadBits
626                 }
627                 return nil
628         }
629
630         lastBH, err := store.GetBlockHeader(b.PreviousBlockId)
631         if err != nil {
632                 return err
633         }
634
635         compareBH, err := store.GetBlockHeader(&lastBH.PreviousBlockHash)
636         if err != nil {
637                 return err
638         }
639
640         for compareBH.Height%consensus.BlocksPerRetarget != 0 {
641                 if compareBH, err = store.GetBlockHeader(&compareBH.PreviousBlockHash); err != nil {
642                         return err
643                 }
644         }
645
646         if b.Bits != difficulty.CalcNextRequiredDifficulty(lastBH, compareBH) {
647                 return errBadBits
648         }
649         return nil
650 }
651
652 func validateBlockTime(b *bc.Block, store database.Store) error {
653         if b.Timestamp > uint64(time.Now().Unix())+consensus.MaxTimeOffsetSeconds {
654                 return errBadTimestamp
655         }
656
657         iterBH, err := store.GetBlockHeader(b.PreviousBlockId)
658         if err != nil {
659                 return err
660         }
661
662         timestamps := []uint64{}
663         for len(timestamps) < consensus.MedianTimeBlocks {
664                 timestamps = append(timestamps, iterBH.Timestamp)
665                 if iterBH.Height == 0 {
666                         break
667                 }
668                 iterBH, err = store.GetBlockHeader(&iterBH.PreviousBlockHash)
669                 if err != nil {
670                         return err
671                 }
672         }
673
674         sort.Sort(common.TimeSorter(timestamps))
675         medianTime := timestamps[len(timestamps)/2]
676         if b.Timestamp <= medianTime {
677                 return errBadTimestamp
678         }
679         return nil
680 }
681
682 func validateCoinbase(tx *bc.Tx, value uint64) error {
683         resultEntry := tx.Entries[*tx.TxHeader.ResultIds[0]]
684         output, ok := resultEntry.(*bc.Output)
685         if !ok {
686                 return errors.Wrap(errWrongCoinbaseTransaction, "decode output")
687         }
688
689         if output.Source.Value.Amount != value {
690                 return errors.Wrap(errWrongCoinbaseTransaction, "dismatch output value")
691         }
692
693         inputEntry := tx.Entries[tx.InputIDs[0]]
694         input, ok := inputEntry.(*bc.Coinbase)
695         if !ok {
696                 return errors.Wrap(errWrongCoinbaseTransaction, "decode input")
697         }
698         if input.Arbitrary != nil && len(input.Arbitrary) > consensus.CoinbaseArbitrarySizeLimit {
699                 return errors.Wrap(errWrongCoinbaseTransaction, "coinbase arbitrary is over size")
700         }
701         return nil
702 }
703
704 func validateBlockAgainstPrev(b, prev *bc.Block) error {
705         if b.Version < prev.Version {
706                 return errors.WithDetailf(errVersionRegression, "previous block verson %d, current block version %d", prev.Version, b.Version)
707         }
708         if b.Height != prev.Height+1 {
709                 return errors.WithDetailf(errMisorderedBlockHeight, "previous block height %d, current block height %d", prev.Height, b.Height)
710         }
711
712         if prev.ID != *b.PreviousBlockId {
713                 return errors.WithDetailf(errMismatchedBlock, "previous block ID %x, current block wants %x", prev.ID.Bytes(), b.PreviousBlockId.Bytes())
714         }
715         return nil
716 }
717
718 func validateStandardTx(tx *bc.Tx) error {
719         for _, id := range tx.InputIDs {
720                 e, ok := tx.Entries[id]
721                 if !ok {
722                         return errors.New("miss tx input entry")
723                 }
724                 if spend, ok := e.(*bc.Spend); ok {
725                         if *spend.WitnessDestination.Value.AssetId != *consensus.BTMAssetID {
726                                 continue
727                         }
728                         spentOutput, err := tx.Output(*spend.SpentOutputId)
729                         if err != nil {
730                                 return errors.Wrap(err, "getting spend prevout")
731                         }
732
733                         if !segwit.IsP2WScript(spentOutput.ControlProgram.Code) {
734                                 return errNotStandardTx
735                         }
736                 }
737         }
738
739         for _, id := range tx.ResultIds {
740                 e, ok := tx.Entries[*id]
741                 if !ok {
742                         return errors.New("miss tx output entry")
743                 }
744                 if output, ok := e.(*bc.Output); ok {
745                         if *output.Source.Value.AssetId != *consensus.BTMAssetID {
746                                 continue
747                         }
748                         if !segwit.IsP2WScript(output.ControlProgram.Code) {
749                                 return errNotStandardTx
750                         }
751                 }
752         }
753         return nil
754 }
755
756 // ValidateTx validates a transaction.
757 func ValidateTx(tx *bc.Tx, block *bc.Block) (*GasState, error) {
758         if block.Version == 1 && tx.Version != 1 {
759                 return nil, errors.WithDetailf(errTxVersion, "block version %d, transaction version %d", block.Version, tx.Version)
760         }
761
762         if tx.TimeRange > timeRangeGash && tx.TimeRange < block.Timestamp {
763                 return nil, errors.New("transaction max timestamp is lower than block's")
764         } else if tx.TimeRange != 0 && tx.TimeRange < block.Height {
765                 return nil, errors.New("transaction max block height is lower than block's")
766         }
767
768         if tx.TxHeader.SerializedSize > consensus.MaxTxSize || tx.TxHeader.SerializedSize == 0 {
769                 return nil, errWrongTransactionSize
770         }
771
772         if len(tx.ResultIds) == 0 {
773                 return nil, errors.New("tx didn't have any output")
774         }
775
776         if len(tx.GasInputIDs) == 0 && tx != block.Transactions[0] {
777                 return nil, errors.New("tx didn't have gas input")
778         }
779
780         if err := validateStandardTx(tx); err != nil {
781                 return nil, err
782         }
783
784         vs := &validationState{
785                 block:   block,
786                 tx:      tx,
787                 entryID: tx.ID,
788                 gasStatus: &GasState{
789                         GasVaild: false,
790                 },
791                 cache: make(map[bc.Hash]error),
792         }
793
794         err := checkValid(vs, tx.TxHeader)
795         return vs.gasStatus, err
796 }