| 57 | ) |
| 58 | |
| 59 | func checkValid(vs *validationState, e bc.Entry) (err error) { |
| 60 | entryID := bc.EntryID(e) |
| 61 | if err, ok := vs.cache[entryID]; ok { |
| 62 | return err |
| 63 | } |
| 64 | |
| 65 | defer func() { |
| 66 | vs.cache[entryID] = err |
| 67 | }() |
| 68 | |
| 69 | switch e := e.(type) { |
| 70 | case *bc.TxHeader: |
| 71 | // This does only part of the work of validating a tx header. The |
| 72 | // block-related parts of tx validation are in ValidateBlock. |
| 73 | if e.MaxTimeMs > 0 { |
| 74 | if e.MaxTimeMs < e.MinTimeMs { |
| 75 | return errors.WithDetailf(errBadTimeRange, "min time %d, max time %d", e.MinTimeMs, e.MaxTimeMs) |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | for i, resID := range e.ResultIds { |
| 80 | resultEntry := vs.tx.Entries[*resID] |
| 81 | vs2 := *vs |
| 82 | vs2.entryID = *resID |
| 83 | err = checkValid(&vs2, resultEntry) |
| 84 | if err != nil { |
| 85 | return errors.Wrapf(err, "checking result %d", i) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | if e.Version == 1 { |
| 90 | if len(e.ResultIds) == 0 { |
| 91 | return errEmptyResults |
| 92 | } |
| 93 | |
| 94 | if e.ExtHash != nil && !e.ExtHash.IsZero() { |
| 95 | return errNonemptyExtHash |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | case *bc.Mux: |
| 100 | err = vm.Verify(NewTxVMContext(vs.tx, e, e.Program, e.WitnessArguments)) |
| 101 | if err != nil { |
| 102 | return errors.Wrap(err, "checking mux program") |
| 103 | } |
| 104 | |
| 105 | for i, src := range e.Sources { |
| 106 | vs2 := *vs |
| 107 | vs2.sourcePos = uint64(i) |
| 108 | err = checkValidSrc(&vs2, src) |
| 109 | if err != nil { |
| 110 | return errors.Wrapf(err, "checking mux source %d", i) |
| 111 | } |
| 112 | } |
| 113 | for i, dest := range e.WitnessDestinations { |
| 114 | vs2 := *vs |
| 115 | vs2.destPos = uint64(i) |
| 116 | err = checkValidDest(&vs2, dest) |