-
Notifications
You must be signed in to change notification settings - Fork 532
/
packet.go
189 lines (163 loc) · 4.54 KB
/
packet.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package scaffolder
import (
"context"
"os"
"path/filepath"
"github.com/gobuffalo/genny/v2"
"github.com/ignite/cli/v29/ignite/pkg/errors"
"github.com/ignite/cli/v29/ignite/pkg/multiformatname"
"github.com/ignite/cli/v29/ignite/templates/field"
"github.com/ignite/cli/v29/ignite/templates/field/datatype"
"github.com/ignite/cli/v29/ignite/templates/ibc"
)
const (
ibcModuleImplementation = "module_ibc.go"
)
// packetOptions represents configuration for the packet scaffolding.
type packetOptions struct {
withoutMessage bool
signer string
}
// newPacketOptions returns a packetOptions with default options.
func newPacketOptions() packetOptions {
return packetOptions{
signer: "creator",
}
}
// PacketOption configures the packet scaffolding.
type PacketOption func(*packetOptions)
// PacketWithoutMessage disables generating sdk compatible messages and tx related APIs.
func PacketWithoutMessage() PacketOption {
return func(o *packetOptions) {
o.withoutMessage = true
}
}
// PacketWithSigner provides a custom signer name for the packet.
func PacketWithSigner(signer string) PacketOption {
return func(m *packetOptions) {
m.signer = signer
}
}
// AddPacket adds a new type stype to scaffolded app by using optional type fields.
func (s Scaffolder) AddPacket(
ctx context.Context,
moduleName,
packetName string,
packetFields,
ackFields []string,
options ...PacketOption,
) error {
// apply options.
o := newPacketOptions()
for _, apply := range options {
apply(&o)
}
mfName, err := multiformatname.NewName(moduleName, multiformatname.NoNumber)
if err != nil {
return err
}
moduleName = mfName.LowerCase
name, err := multiformatname.NewName(packetName)
if err != nil {
return err
}
if err := checkComponentValidity(s.appPath, moduleName, name, o.withoutMessage); err != nil {
return err
}
mfSigner, err := multiformatname.NewName(o.signer)
if err != nil {
return err
}
// Module must implement IBC
ok, err := isIBCModule(s.appPath, moduleName)
if err != nil {
return err
}
if !ok {
return errors.Errorf("the module %s doesn't implement IBC module interface", moduleName)
}
signer := ""
if !o.withoutMessage {
signer = o.signer
}
// Check and parse packet fields
if err := checkCustomTypes(ctx, s.appPath, s.modpath.Package, s.protoDir, moduleName, packetFields); err != nil {
return err
}
parsedPacketFields, err := field.ParseFields(packetFields, checkForbiddenPacketField, signer)
if err != nil {
return err
}
// check and parse acknowledgment fields
if err := checkCustomTypes(ctx, s.appPath, s.modpath.Package, s.protoDir, moduleName, ackFields); err != nil {
return err
}
parsedAcksFields, err := field.ParseFields(ackFields, checkGoReservedWord, signer)
if err != nil {
return err
}
// Generate the packet
var (
g *genny.Generator
opts = &ibc.PacketOptions{
AppName: s.modpath.Package,
AppPath: s.appPath,
ProtoDir: s.protoDir,
ProtoVer: "v1", // TODO(@julienrbrt): possibly in the future add flag to specify custom proto version.
ModulePath: s.modpath.RawPath,
ModuleName: moduleName,
PacketName: name,
Fields: parsedPacketFields,
AckFields: parsedAcksFields,
NoMessage: o.withoutMessage,
MsgSigner: mfSigner,
}
)
g, err = ibc.NewPacket(s.Tracer(), opts)
if err != nil {
return err
}
return s.Run(g)
}
// isIBCModule returns true if the provided module implements the IBC module interface
// we naively check the existence of module_ibc.go for this check.
func isIBCModule(appPath string, moduleName string) (bool, error) {
absPath, err := filepath.Abs(filepath.Join(appPath, moduleDir, moduleName, modulePkg, ibcModuleImplementation))
if err != nil {
return false, err
}
_, err = os.Stat(absPath)
if err != nil && !os.IsNotExist(err) {
return false, err
} else if err == nil {
// Is an IBC module
return true, err
}
// check the legacy Path
absPathLegacy, err := filepath.Abs(filepath.Join(appPath, moduleDir, moduleName, ibcModuleImplementation))
if err != nil {
return false, err
}
_, err = os.Stat(absPathLegacy)
if os.IsNotExist(err) {
// Not an IBC module
return false, nil
}
return true, err
}
// checkForbiddenPacketField returns true if the name is forbidden as a packet name.
func checkForbiddenPacketField(name string) error {
mfName, err := multiformatname.NewName(name)
if err != nil {
return err
}
switch mfName.LowerCase {
case
"sender",
"port",
"channelid",
datatype.TypeCustom:
return errors.Errorf("%s is used by the packet scaffolder", name)
}
return checkGoReservedWord(name)
}