-
Notifications
You must be signed in to change notification settings - Fork 95
/
input.go
127 lines (104 loc) · 3.62 KB
/
input.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package iotago
import (
"fmt"
"github.com/iotaledger/hive.go/constraints"
"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/hive.go/serializer/v2"
)
// InputType defines the type of inputs.
type InputType byte
const (
// InputUTXO is a type of input which references an unspent transaction output.
InputUTXO InputType = iota
)
func (inputType InputType) String() string {
if int(inputType) >= len(inputNames) {
return fmt.Sprintf("unknown input type: %d", inputType)
}
return inputNames[inputType]
}
var inputNames = [InputUTXO + 1]string{"UTXOInput"}
var (
// ErrRefUTXOIndexInvalid gets returned on invalid UTXO indices.
ErrRefUTXOIndexInvalid = ierrors.Errorf("the referenced UTXO index must be between %d and %d (inclusive)", RefUTXOIndexMin, RefUTXOIndexMax)
)
// Inputs is a slice of Input.
type Inputs[T Input] []T
func (in Inputs[T]) Clone() Inputs[T] {
cpy := make(Inputs[T], len(in))
for idx, input := range in {
//nolint:forcetypeassert // we can safely assume that this is of type T
cpy[idx] = input.Clone().(T)
}
return cpy
}
func (in Inputs[T]) Size() int {
sum := serializer.UInt16ByteSize
for _, i := range in {
sum += i.Size()
}
return sum
}
func (in Inputs[T]) WorkScore(workScoreParameters *WorkScoreParameters) (WorkScore, error) {
var workScoreInputs WorkScore
for _, input := range in {
workScoreInput, err := input.WorkScore(workScoreParameters)
if err != nil {
return 0, err
}
workScoreInputs, err = workScoreInputs.Add(workScoreInput)
if err != nil {
return 0, err
}
}
return workScoreInputs, nil
}
// Input references a generic input.
type Input interface {
Sizer
constraints.Cloneable[Input]
ProcessableObject
// Type returns the type of Input.
Type() InputType
}
// InputsSyntacticalUnique returns an ElementValidationFunc which checks that every input has a unique reference UTXO index.
func InputsSyntacticalUnique() ElementValidationFunc[Input] {
utxoSet := map[string]int{}
return func(index int, input Input) error {
switch castInput := input.(type) {
case *UTXOInput:
referencedOutputID := castInput.OutputID()
k := string(referencedOutputID[:])
if j, has := utxoSet[k]; has {
return ierrors.WithMessagef(ErrInputUTXORefsNotUnique, "input %d and %d share the same referenced UTXO index", j, index)
}
utxoSet[k] = index
default:
// We're switching on the Go input type here, so we can only run into the default case
// if we added a new input type and have not handled it above or a user constructed a type
// implementing the interface (only possible when iota.go is used as a library).
// In both cases we want to panic.
panic("all supported input types should be handled above")
}
return nil
}
}
// InputsSyntacticalIndicesWithinBounds returns an ElementValidationFunc which checks that the UTXO ref index is within bounds.
func InputsSyntacticalIndicesWithinBounds() ElementValidationFunc[Input] {
return func(index int, input Input) error {
switch castInput := input.(type) {
case *UTXOInput:
// TODO: do we really want to check the max value on the input side?
if castInput.Index() < RefUTXOIndexMin || castInput.Index() > RefUTXOIndexMax {
return ierrors.WithMessagef(ErrRefUTXOIndexInvalid, "input %d", index)
}
default:
// We're switching on the Go input type here, so we can only run into the default case
// if we added a new input type and have not handled it above or a user constructed a type
// implementing the interface (only possible when iota.go is used as a library).
// In both cases we want to panic.
panic("all supported input types should be handled above")
}
return nil
}
}