-
Notifications
You must be signed in to change notification settings - Fork 95
/
root.go
215 lines (188 loc) · 5.33 KB
/
root.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
204
205
206
207
208
209
210
211
212
213
214
215
// Copyright 2020 Coinbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"encoding/json"
"io/ioutil"
"log"
"path"
"time"
"github.com/coinbase/rosetta-cli/internal/reconciler"
"github.com/spf13/cobra"
)
const (
// ExtendedRetryElapsedTime is used to override the default fetcher
// retry elapsed time. In practice, extending the retry elapsed time
// has prevented retry exhaustion errors when many goroutines are
// used to fetch data from the Rosetta server.
//
// TODO: make configurable
ExtendedRetryElapsedTime = 5 * time.Minute
)
var (
rootCmd = &cobra.Command{
Use: "rosetta-cli",
Short: "CLI for the Rosetta API",
}
// DataDir is a folder used to store logs
// and any data used to perform validation.
DataDir string
// ServerURL is the base URL for a Rosetta
// server to validate.
ServerURL string
// StartIndex is the block index to start syncing.
StartIndex int64
// EndIndex is the block index to stop syncing.
EndIndex int64
// BlockConcurrency is the concurrency to use
// while fetching blocks.
BlockConcurrency uint64
// TransactionConcurrency is the concurrency to use
// while fetching transactions (if required).
TransactionConcurrency uint64
// AccountConcurrency is the concurrency to use
// while fetching accounts during reconciliation.
AccountConcurrency uint64
// LogBlocks determines if blocks are
// logged.
LogBlocks bool
// LogTransactions determines if transactions are
// logged.
LogTransactions bool
// LogBalanceChanges determines if balance changes are
// logged.
LogBalanceChanges bool
// LogReconciliations determines if reconciliations are
// logged.
LogReconciliations bool
// HaltOnReconciliationError determines if processing
// should stop when encountering a reconciliation error.
// It can be beneficial to collect all reconciliation errors
// during development.
HaltOnReconciliationError bool
// ExemptFile is an absolute path to a file listing all accounts
// to exempt from balance tracking and reconciliation.
ExemptFile string
)
// Execute handles all invocations of the
// rosetta-cli cmd.
func Execute() error {
return rootCmd.Execute()
}
func init() {
rootCmd.PersistentFlags().StringVar(
&DataDir,
"data-dir",
"./validator-data",
"folder used to store logs and any data used to perform validation",
)
rootCmd.PersistentFlags().StringVar(
&ServerURL,
"server-url",
"http://localhost:8080",
"base URL for a Rosetta server to validate",
)
rootCmd.PersistentFlags().Int64Var(
&StartIndex,
"start",
-1,
"block index to start syncing",
)
rootCmd.PersistentFlags().Int64Var(
&EndIndex,
"end",
-1,
"block index to stop syncing",
)
rootCmd.PersistentFlags().Uint64Var(
&BlockConcurrency,
"block-concurrency",
8,
"concurrency to use while fetching blocks",
)
rootCmd.PersistentFlags().Uint64Var(
&TransactionConcurrency,
"transaction-concurrency",
16,
"concurrency to use while fetching transactions (if required)",
)
rootCmd.PersistentFlags().Uint64Var(
&AccountConcurrency,
"account-concurrency",
8,
"concurrency to use while fetching accounts during reconciliation",
)
rootCmd.PersistentFlags().BoolVar(
&LogBlocks,
"log-blocks",
false,
"log processed blocks",
)
rootCmd.PersistentFlags().BoolVar(
&LogTransactions,
"log-transactions",
false,
"log processed transactions",
)
rootCmd.PersistentFlags().BoolVar(
&LogBalanceChanges,
"log-balance-changes",
false,
"log balance changes",
)
rootCmd.PersistentFlags().BoolVar(
&LogReconciliations,
"log-reconciliations",
false,
"log balance reconciliations",
)
rootCmd.PersistentFlags().BoolVar(
&HaltOnReconciliationError,
"halt-on-reconciliation-error",
true,
`Determines if block processing should halt on a reconciliation
error. It can be beneficial to collect all reconciliation errors or silence
reconciliation errors during development.`,
)
rootCmd.PersistentFlags().StringVar(
&ExemptFile,
"exempt-accounts",
"",
`Absolute path to a file listing all accounts to exempt from balance
tracking and reconciliation. Look at the examples directory for an example of
how to structure this file.`,
)
rootCmd.AddCommand(checkCompleteCmd)
rootCmd.AddCommand(checkQuickCmd)
rootCmd.AddCommand(checkAccountCmd)
}
func loadAccounts(filePath string) ([]*reconciler.AccountCurrency, error) {
if len(filePath) == 0 {
return []*reconciler.AccountCurrency{}, nil
}
accountsRaw, err := ioutil.ReadFile(path.Clean(filePath))
if err != nil {
return nil, err
}
accounts := []*reconciler.AccountCurrency{}
if err := json.Unmarshal(accountsRaw, &accounts); err != nil {
return nil, err
}
prettyAccounts, err := json.MarshalIndent(accounts, "", " ")
if err != nil {
return nil, err
}
log.Printf("Found %d accounts at %s: %s\n", len(accounts), filePath, string(prettyAccounts))
return accounts, nil
}