/
cmds_write.go
163 lines (148 loc) 路 4.16 KB
/
cmds_write.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
package model
import (
"regexp"
"strings"
log "github.com/sirupsen/logrus"
)
type WriteCmds map[string]*WriteCmdSpec
func (cmds WriteCmds) Validate(ctx AppContext, spec *Spec) bool {
validateLog := log.WithFields(log.Fields{
"section": "WriteCmds",
"func": "Validate",
})
for name, cmd := range cmds {
if _, ok := spec.uniqueNames[name]; ok {
validateLog.WithField("name", name).Errorln("cmd name is not unique")
return false
}
spec.uniqueNames[name] = struct{}{}
if ctx.AppCommand() == name {
if !cmd.Validate(ctx, name, spec) {
return false
}
}
}
return true
}
func (cmds WriteCmds) WriteCmdSpec(name string) (*WriteCmdSpec, bool) {
spec, ok := cmds[name]
return spec, ok
}
type WriteCmdSpec struct {
ParamSpec `yaml:",inline"`
Description string `yaml:"desc"`
Wallet string `yaml:"wallet"`
Sticky string `yaml:"sticky"`
To string `yaml:"to"`
Value Valuer `yaml:"value"`
Method string `yaml:"method"`
Instance *ContractInstanceSpec `yaml:"instance"`
walletRx *regexp.Regexp `yaml:"-"`
matching *WalletSpec `yaml:"-"`
}
func (spec *WriteCmdSpec) Validate(ctx AppContext, name string, root *Spec) bool {
validateLog := log.WithFields(log.Fields{
"section": "WriteCommands",
"command": name,
})
var hasWalletName bool
if len(spec.Wallet) > 0 {
if isWalletRef(spec.Wallet) {
validateLog.Errorln("wallet reference is not allowed in 'wallet' field, must be name")
return false
}
hasWalletName = true
} else {
// match all by default
spec.Wallet = "."
}
rx, err := regexp.Compile(spec.Wallet)
if err != nil {
validateLog.WithError(err).Errorln("failed to compile wallet regexp")
return false
}
spec.walletRx = rx
if len(spec.Sticky) == 0 {
spec.Sticky = name
}
spec.matching = root.Wallets.GetOne(spec.walletRx, spec.Sticky)
if hasWalletName {
if spec.matching == nil {
validateLog.Errorln("no wallets are matching the specified regexp")
return false
}
} else {
validateLog.Errorln("no wallets specified to send from")
return false
}
if len(spec.To) == 0 {
if spec.Instance == nil {
validateLog.Errorln("no recipient contract instance specified")
return false
} else if len(spec.Instance.Name) == 0 {
validateLog.Errorln("the recipient contract spec name is not specified")
return false
}
contract, ok := root.Contracts.ContractSpec(spec.Instance.Name)
if !ok || contract == nil {
validateLog.Errorln("the recipient contract spec not found (name mismatch)")
return false
} else if len(contract.Instances) == 0 {
validateLog.Errorln("the recipient contract spec has no instances")
return false
}
address := strings.ToLower(spec.Instance.Address)
if len(address) == 0 {
spec.Instance = contract.Instances[0]
} else {
var found bool
for _, instance := range contract.Instances {
if strings.ToLower(instance.Address) == address {
found = true
spec.Instance = instance
break
}
}
if !found {
validateLog.Errorln("referenced contract instance is not found (address mismatch)")
return false
}
}
// TODO: check ABI
} else if spec.Instance != nil {
validateLog.Errorln("contract instance must not be specified while using recipient 'to' address")
return false
} else {
if isWalletRef(spec.To) {
validateLog.Errorln("wallet reference is not allowed in 'to' field, must be name")
return false
}
if spec.To != ZeroAddress {
if wallet, ok := root.Wallets.WalletSpec(spec.To); !ok {
validateLog.Errorln("recipient 'to' wallet name is not found")
return false
} else if wallet.Address == "" || wallet.Address == ZeroAddress {
validateLog.Errorln("recipient 'to' wallet has no address. For 0x0, use '0x0' instead of name")
return false
} else {
spec.To = wallet.Address
}
}
}
if !spec.ParamSpec.Validate(ctx, name, root) {
return false
}
return true
}
func (spec *WriteCmdSpec) MatchingWallet() *WalletSpec {
return spec.matching
}
func (spec *WriteCmdSpec) CountArgsUsing(set map[int]struct{}) {
spec.ParamSpec.CountArgsUsing(set)
spec.Value.CountArgsUsing(set)
}
func (spec *WriteCmdSpec) ArgCount() int {
set := make(map[int]struct{})
spec.CountArgsUsing(set)
return len(set)
}