-
Notifications
You must be signed in to change notification settings - Fork 127
/
mint.go
127 lines (110 loc) · 2.54 KB
/
mint.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 common
import (
"fmt"
"github.com/MixinNetwork/mixin/crypto"
)
const (
mintGroupUniversal = "UNIVERSAL"
)
type MintData struct {
Group string
Batch uint64
Amount Integer
}
type MintDistribution struct {
MintData
Transaction crypto.Hash
}
func (m *MintData) Distribute(tx crypto.Hash) *MintDistribution {
return &MintDistribution{
MintData: *m,
Transaction: tx,
}
}
func (tx *VersionedTransaction) validateMint(store DataStore) error {
if len(tx.Inputs) != 1 {
return fmt.Errorf("invalid inputs count %d for mint", len(tx.Inputs))
}
for _, out := range tx.Outputs {
if out.Type != OutputTypeScript {
return fmt.Errorf("invalid mint output type %d", out.Type)
}
}
if tx.Asset != XINAssetId {
return fmt.Errorf("invalid mint asset %s", tx.Asset.String())
}
mint := tx.Inputs[0].Mint
switch mint.Group {
case mintGroupUniversal:
default:
return fmt.Errorf("invalid mint group %s", mint.Group)
}
dist, err := store.ReadLastMintDistribution(^uint64(0))
if err != nil || dist == nil {
return err
}
if mint.Batch < dist.Batch {
return fmt.Errorf("backward mint batch %d %d", dist.Batch, mint.Batch)
}
if mint.Batch > dist.Batch {
return nil
}
if dist.Transaction != tx.PayloadHash() || dist.Amount.Cmp(mint.Amount) != 0 {
return fmt.Errorf("invalid mint lock %s %s", dist.Transaction.String(), tx.PayloadHash().String())
}
return nil
}
func (tx *Transaction) AddUniversalMintInput(batch uint64, amount Integer) {
tx.Inputs = append(tx.Inputs, &Input{
Mint: &MintData{
Group: mintGroupUniversal,
Batch: batch,
Amount: amount,
},
})
}
func (m *MintDistribution) Marshal() []byte {
enc := NewMinimumEncoder()
switch m.Group {
case mintGroupUniversal:
enc.WriteUint16(0x0)
default:
panic(m.Group)
}
enc.WriteUint64(m.Batch)
enc.WriteInteger(m.Amount)
enc.Write(m.Transaction[:])
return enc.Bytes()
}
func UnmarshalMintDistribution(b []byte) (*MintDistribution, error) {
if len(b) < 16 {
return nil, fmt.Errorf("invalid mint distribution size %d", len(b))
}
var m MintDistribution
dec, err := NewMinimumDecoder(b)
if err != nil {
return nil, err
}
group, err := dec.ReadUint16()
if err != nil {
return nil, err
}
switch group {
case 0x0:
m.Group = mintGroupUniversal
default:
return nil, fmt.Errorf("invalid mint distribution group %d", group)
}
batch, err := dec.ReadUint64()
if err != nil {
return nil, err
}
m.Batch = batch
amount, err := dec.ReadInteger()
if err != nil {
return nil, err
}
m.Amount = amount
err = dec.Read(m.Transaction[:])
return &m, err
}