-
Notifications
You must be signed in to change notification settings - Fork 5
/
create.go
169 lines (135 loc) · 4.31 KB
/
create.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
Copyright Gen Digital Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package operationparser
import (
"encoding/json"
"errors"
"fmt"
"github.com/trustbloc/sidetree-go/pkg/api/operation"
"github.com/trustbloc/sidetree-go/pkg/canonicalizer"
"github.com/trustbloc/sidetree-go/pkg/hashing"
"github.com/trustbloc/sidetree-go/pkg/patch"
"github.com/trustbloc/sidetree-go/pkg/versions/1_0/model"
"github.com/trustbloc/sidetree-go/pkg/versions/1_0/operationparser/patchvalidator"
)
// ParseCreateOperation will parse create operation.
func (p *Parser) ParseCreateOperation(request []byte, batch bool) (*model.Operation, error) {
schema, err := p.parseCreateRequest(request)
if err != nil {
return nil, err
}
// create is not valid if suffix data is not valid
err = p.ValidateSuffixData(schema.SuffixData)
if err != nil {
return nil, err
}
if !batch {
err = p.anchorOriginValidator.Validate(schema.SuffixData.AnchorOrigin)
if err != nil {
return nil, err
}
err = p.ValidateDelta(schema.Delta)
if err != nil {
return nil, err
}
// verify actual delta hash matches expected delta hash
err = hashing.IsValidModelMultihash(schema.Delta, schema.SuffixData.DeltaHash)
if err != nil {
return nil, fmt.Errorf("delta doesn't match suffix data delta hash: %s", err.Error())
}
if schema.Delta.UpdateCommitment == schema.SuffixData.RecoveryCommitment {
return nil, errors.New("recovery and update commitments cannot be equal, re-using public keys is not allowed")
}
}
uniqueSuffix, err := model.GetUniqueSuffix(schema.SuffixData, p.MultihashAlgorithms)
if err != nil {
return nil, err
}
return &model.Operation{
OperationRequest: request,
Type: operation.TypeCreate,
UniqueSuffix: uniqueSuffix,
Delta: schema.Delta,
SuffixData: schema.SuffixData,
AnchorOrigin: schema.SuffixData.AnchorOrigin,
}, nil
}
// parseCreateRequest parses a 'create' request.
func (p *Parser) parseCreateRequest(payload []byte) (*model.CreateRequest, error) {
schema := &model.CreateRequest{}
err := json.Unmarshal(payload, schema)
if err != nil {
return nil, err
}
return schema, nil
}
// ValidateDelta validates delta.
func (p *Parser) ValidateDelta(delta *model.DeltaModel) error {
if delta == nil {
return errors.New("missing delta")
}
if len(delta.Patches) == 0 {
return errors.New("missing patches")
}
for _, ptch := range delta.Patches {
action, err := ptch.GetAction()
if err != nil {
return err
}
if !p.isPatchEnabled(action) {
return fmt.Errorf("%s patch action is not enabled", action)
}
if err := patchvalidator.Validate(ptch); err != nil {
return err
}
}
if err := p.validateMultihash(delta.UpdateCommitment, "update commitment"); err != nil {
return err
}
return p.validateDeltaSize(delta)
}
func (p *Parser) validateMultihash(mh, alias string) error {
if len(mh) > int(p.MaxOperationHashLength) {
return fmt.Errorf("%s length[%d] exceeds maximum hash length[%d]", alias, len(mh), p.MaxOperationHashLength)
}
if !hashing.IsComputedUsingMultihashAlgorithms(mh, p.MultihashAlgorithms) {
return fmt.Errorf("%s is not computed with the required hash algorithms: %d", alias, p.MultihashAlgorithms)
}
return nil
}
func (p *Parser) validateDeltaSize(delta *model.DeltaModel) error {
canonicalDelta, err := canonicalizer.MarshalCanonical(delta)
if err != nil {
return fmt.Errorf("marshal canonical for delta failed: %s", err.Error())
}
if len(canonicalDelta) > int(p.MaxDeltaSize) {
return fmt.Errorf("delta size[%d] exceeds maximum delta size[%d]", len(canonicalDelta), p.MaxDeltaSize)
}
return nil
}
func (p *Parser) isPatchEnabled(action patch.Action) bool {
for _, allowed := range p.Patches {
if patch.Action(allowed) == action {
return true
}
}
return false
}
// ValidateSuffixData validates suffix data.
func (p *Parser) ValidateSuffixData(suffixData *model.SuffixDataModel) error {
if suffixData == nil {
return errors.New("missing suffix data")
}
if err := p.validateMultihash(suffixData.RecoveryCommitment, "recovery commitment"); err != nil {
return err
}
return p.validateMultihash(suffixData.DeltaHash, "delta hash")
}
func (p *Parser) validateCreateRequest(create *model.CreateRequest) error {
if create.SuffixData == nil {
return errors.New("missing suffix data")
}
return nil
}