OSDN Git Service

Merge branch 'master' into develop
[bytom/bytom.git] / protocol / tx.go
1 package protocol
2
3 import (
4         "sync"
5
6         "github.com/golang/groupcache/lru"
7
8         "github.com/bytom/errors"
9         "github.com/bytom/protocol/bc"
10         "github.com/bytom/protocol/validation"
11 )
12
13 // ErrBadTx is returned for transactions failing validation
14 var ErrBadTx = errors.New("invalid transaction")
15
16 // ValidateTx validates the given transaction. A cache holds
17 // per-transaction validation results and is consulted before
18 // performing full validation.
19 func (c *Chain) ValidateTx(tx *bc.Tx) error {
20         err := c.checkIssuanceWindow(tx)
21         if err != nil {
22                 return err
23         }
24         var ok bool
25         err, ok = c.prevalidated.lookup(tx.ID)
26         if !ok {
27                 err = validation.ValidateTx(tx, c.InitialBlockHash)
28                 c.prevalidated.cache(tx.ID, err)
29         }
30         return errors.Sub(ErrBadTx, err)
31 }
32
33 type prevalidatedTxsCache struct {
34         mu  sync.Mutex
35         lru *lru.Cache
36 }
37
38 func (c *prevalidatedTxsCache) lookup(txID bc.Hash) (err error, ok bool) {
39         c.mu.Lock()
40         v, ok := c.lru.Get(txID)
41         c.mu.Unlock()
42         if !ok {
43                 return err, ok
44         }
45         if v == nil {
46                 return nil, ok
47         }
48         return v.(error), ok
49 }
50
51 func (c *prevalidatedTxsCache) cache(txID bc.Hash, err error) {
52         c.mu.Lock()
53         c.lru.Add(txID, err)
54         c.mu.Unlock()
55 }
56
57 func (c *Chain) checkIssuanceWindow(tx *bc.Tx) error {
58         if c.MaxIssuanceWindow == 0 {
59                 return nil
60         }
61         for _, entryID := range tx.InputIDs {
62                 if _, err := tx.Issuance(entryID); err == nil {
63                         if tx.MinTimeMs+bc.DurationMillis(c.MaxIssuanceWindow) < tx.MaxTimeMs {
64                                 return errors.WithDetailf(ErrBadTx, "issuance input's time window is larger than the network maximum (%s)", c.MaxIssuanceWindow)
65                         }
66                 }
67         }
68         return nil
69 }