-
Notifications
You must be signed in to change notification settings - Fork 0
/
matcher.go
203 lines (174 loc) · 6.07 KB
/
matcher.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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package main
import (
"regexp"
"strings"
)
// MatchWithMode matches the candidate string with the specified mode in the matcher.
// It returns true if the candidate matches the mode, otherwise false.
func (m matcher) MatchWithMode(candidate string) bool {
switch m.Mode {
case "contains":
return strings.Contains(candidate, m.SearchString)
case "starts-with":
return strings.HasPrefix(candidate, m.SearchString)
case "ends-with":
return strings.HasSuffix(candidate, m.SearchString)
case "regex":
match, err := regexp.MatchString(m.SearchString, candidate)
if err != nil {
return false
}
return match
default:
return strings.Contains(candidate, m.SearchString)
}
}
// Match checks if the candidate string matches the criteria specified in the matcher.
// It trims the prefix from the candidate, checks the required amount of digits and letters,
// and then calls MatchWithMode to perform the matching based on the mode.
// It returns true if the candidate matches the criteria, otherwise false.
func (m matcher) Match(candidate string) bool {
candidate = strings.TrimPrefix(candidate, m.Chain.PrefixFull)
if !m.CheckRequiredDigits(candidate, m.RequiredDigits) {
return false
}
if !m.CheckRequiredLetters(candidate, m.RequiredLetters) {
return false
}
return m.MatchWithMode(candidate)
}
// ValidateInput validates the input parameters of the matcher and returns any validation errors.
// It dynamically selects the appropriate generator based on the encryption type in the chain,
// and then calls the generator's ValidateInput method.
// It returns a slice of validation error messages.
func (m matcher) ValidateInput() []string {
var generatorValidate func(SearchString string, RequiredLetters, RequiredDigits int) []string
switch m.Chain.Encryption {
case Secp256k1:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
generatorValidate = secp256k1generator.ValidateInput
case ECSDA:
var ecsdagenerator = ecsdaWallet{
Chain: m.Chain,
}
generatorValidate = ecsdagenerator.ValidateInput
default:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
generatorValidate = secp256k1generator.ValidateInput
}
return generatorValidate(m.SearchString, m.RequiredLetters, m.RequiredDigits)
}
// CheckRequiredDigits checks if the candidate string contains the required amount of digits.
// It dynamically selects the appropriate generator based on the encryption type in the chain,
// and then calls the generator's CheckRequiredDigits method.
// It returns true if the candidate contains the required amount of digits, otherwise false.
func (m matcher) CheckRequiredDigits(candidate string, required int) bool {
var gcrd func(candidate string, required int) bool
switch m.Chain.Encryption {
case Secp256k1:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
gcrd = secp256k1generator.CheckRequiredDigits
case ECSDA:
var ecsdagenerator = ecsdaWallet{
Chain: m.Chain,
}
gcrd = ecsdagenerator.CheckRequiredDigits
default:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
gcrd = secp256k1generator.CheckRequiredDigits
}
return gcrd(candidate, required)
}
// CheckRequiredLetters checks if the candidate string contains the required amount of letters.
// It dynamically selects the appropriate generator based on the encryption type in the chain,
// and then calls the generator's CheckRequiredLetters method.
// It returns true if the candidate contains the required amount of letters, otherwise false.
func (m matcher) CheckRequiredLetters(candidate string, required int) bool {
var gcrl func(candidate string, required int) bool
switch m.Chain.Encryption {
case Secp256k1:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
gcrl = secp256k1generator.CheckRequiredLetters
case ECSDA:
var ecsdagenerator = ecsdaWallet{
Chain: m.Chain,
}
gcrl = ecsdagenerator.CheckRequiredLetters
default:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
gcrl = secp256k1generator.CheckRequiredLetters
}
return gcrl(candidate, required)
}
// GenerateWallet generates a wallet based on the encryption type in the chain.
// It dynamically selects the appropriate generator based on the encryption type in the chain,
// and then calls the generator's GenerateWallet method.
// It returns the generated wallet.
func (m matcher) GenerateWallet() wallet {
var generate func() wallet
switch m.Chain.Encryption {
case Secp256k1:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
generate = secp256k1generator.GenerateWallet
case ECSDA:
var ecsdagenerator = ecsdaWallet{
Chain: m.Chain,
}
generate = ecsdagenerator.GenerateWallet
default:
var secp256k1generator = secp256k1Wallet{
Chain: m.Chain,
}
generate = secp256k1generator.GenerateWallet
}
return generate()
}
// findMatchingWallets finds matching wallets based on the matcher criteria and sends them to the channel.
// It runs in a loop until the quit signal is received.
// It generates a wallet using the GenerateWallet method and checks if it matches the criteria using the Match method.
// If a match is found, it sends the wallet to the channel.
func findMatchingWallets(ch chan wallet, quit chan struct{}, m matcher) {
for {
select {
case <-quit:
return
default:
w := m.GenerateWallet()
if m.Match(w.Address) {
// Do a non-blocking write instead of simple `ch <- w` to prevent
// blocking when it's time to quit and ch is full.
select {
case ch <- w:
default:
}
}
}
}
}
// findMatchingWalletConcurrent finds a matching wallet concurrently using multiple goroutines.
// It creates a channel for sending and receiving wallets, and a quit channel for signaling the goroutines to stop.
// It spawns the specified number of goroutines, each running the findMatchingWallets function.
// It returns the first matching wallet received from the channel.
func findMatchingWalletConcurrent(m matcher, goroutines int) wallet {
ch := make(chan wallet)
quit := make(chan struct{})
defer close(quit)
for i := 0; i < goroutines; i++ {
go findMatchingWallets(ch, quit, m)
}
return <-ch
}