@@ -18,7 +18,6 @@ package libgoal
18
18
19
19
import (
20
20
"fmt"
21
- "io/ioutil"
22
21
"math"
23
22
"os"
24
23
"path/filepath"
@@ -27,76 +26,34 @@ import (
27
26
"github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated"
28
27
"github.com/algorand/go-algorand/data/account"
29
28
"github.com/algorand/go-algorand/data/basics"
30
- "github.com/algorand/go-algorand/protocol"
31
29
"github.com/algorand/go-algorand/util/db"
32
30
)
33
31
34
32
// chooseParticipation chooses which participation keys to use for going online
35
33
// based on the address, round number, and available participation databases
36
- func (c * Client ) chooseParticipation (address basics.Address , round basics.Round ) (part account. Participation , err error ) {
37
- genID , err := c .GenesisID ()
34
+ func (c * Client ) chooseParticipation (address basics.Address , round basics.Round ) (part generated. ParticipationKey , err error ) {
35
+ parts , err := c .ListParticipationKeys ()
38
36
if err != nil {
39
37
return
40
38
}
41
39
42
- // Get a list of files in the participation keys directory
43
- keyDir := filepath .Join (c .DataDir (), genID )
44
- files , err := ioutil .ReadDir (keyDir )
45
- if err != nil {
46
- return
47
- }
48
- // This lambda will be used for finding the desired file.
49
- checkIfFileIsDesiredKey := func (file os.FileInfo , expiresAfter basics.Round ) (part account.Participation , err error ) {
50
- var handle db.Accessor
51
- var partCandidate account.PersistedParticipation
52
-
53
- // If it can't be a participation key database, skip it
54
- if ! config .IsPartKeyFilename (file .Name ()) {
55
- return
56
- }
57
-
58
- filename := file .Name ()
59
-
60
- // Fetch a handle to this database
61
- handle , err = db .MakeErasableAccessor (filepath .Join (keyDir , filename ))
62
- if err != nil {
63
- // Couldn't open it, skip it
64
- return
65
- }
66
-
67
- // Fetch an account.Participation from the database
68
- partCandidate , err = account .RestoreParticipation (handle )
69
- if err != nil {
70
- // Couldn't read it, skip it
71
- handle .Close ()
72
- return
73
- }
74
- defer partCandidate .Close ()
75
-
76
- // Return the Participation valid for this round that relates to the passed address
40
+ // Loop through each of the participation keys; pick the one that expires farthest in the future.
41
+ var expiry uint64 = 0
42
+ for _ , info := range parts {
43
+ // Choose the Participation valid for this round that relates to the passed address
77
44
// that expires farthest in the future.
78
45
// Note that algod will sign votes with all possible Participations. so any should work
79
46
// in the short-term.
80
47
// In the future we should allow the user to specify exactly which partkeys to register.
81
- if partCandidate .FirstValid <= round && round <= partCandidate .LastValid && partCandidate .Parent == address && partCandidate .LastValid > expiresAfter {
82
- part = partCandidate .Participation
48
+ if info .Key .VoteFirstValid <= uint64 (round ) && uint64 (round ) <= info .Key .VoteLastValid && info .Address == address .String () && info .Key .VoteLastValid > expiry {
49
+ part = info
50
+ expiry = part .Key .VoteLastValid
83
51
}
84
- return
85
- }
86
52
87
- // Loop through each of the files; pick the one that expires farthest in the future.
88
- var expiry basics.Round
89
- for _ , info := range files {
90
- // Use above lambda so the deferred handle closure happens each loop
91
- partCandidate , err := checkIfFileIsDesiredKey (info , expiry )
92
- if err == nil && (! partCandidate .Parent .IsZero ()) {
93
- part = partCandidate
94
- expiry = part .LastValid
95
- }
96
53
}
97
- if part .Parent . IsZero () {
54
+ if part .Address == "" {
98
55
// Couldn't find one
99
- err = fmt .Errorf ("Couldn 't find a participation key database for address %v valid at round %v in directory %v " , address .GetUserAddress (), round , keyDir )
56
+ err = fmt .Errorf ("couldn 't find a participation key database for address %v valid at round %v in participation registry " , address .GetUserAddress (), round )
100
57
return
101
58
}
102
59
return
@@ -117,8 +74,12 @@ func (c *Client) GenParticipationKeys(address string, firstValid, lastValid, key
117
74
}
118
75
119
76
// GenParticipationKeysTo creates a .partkey database for a given address, fills
120
- // it with keys, and saves it in the specified output directory.
77
+ // it with keys, and saves it in the specified output directory. If the output
78
+ // directory is empty, the key will be installed.
121
79
func (c * Client ) GenParticipationKeysTo (address string , firstValid , lastValid , keyDilution uint64 , outDir string ) (part account.Participation , filePath string , err error ) {
80
+
81
+ install := outDir == ""
82
+
122
83
// Parse the address
123
84
parsedAddr , err := basics .UnmarshalChecksumAddress (address )
124
85
if err != nil {
@@ -127,16 +88,9 @@ func (c *Client) GenParticipationKeysTo(address string, firstValid, lastValid, k
127
88
128
89
firstRound , lastRound := basics .Round (firstValid ), basics .Round (lastValid )
129
90
130
- // If output directory wasn't specified, store it in the current ledger directory.
131
- if outDir == "" {
132
- // Get the GenesisID for use in the participation key path
133
- var genID string
134
- genID , err = c .GenesisID ()
135
- if err != nil {
136
- return
137
- }
138
-
139
- outDir = filepath .Join (c .DataDir (), genID )
91
+ // If we are installing, generate in the temp dir
92
+ if install {
93
+ outDir = os .TempDir ()
140
94
}
141
95
// Connect to the database
142
96
partKeyPath , err := participationKeysPath (outDir , parsedAddr , firstRound , lastRound )
@@ -152,6 +106,14 @@ func (c *Client) GenParticipationKeysTo(address string, firstValid, lastValid, k
152
106
return
153
107
}
154
108
109
+ // If the key is being installed, remove it afterwards.
110
+ if install {
111
+ // Explicitly ignore any errors
112
+ defer func (name string ) {
113
+ _ = os .Remove (name )
114
+ }(partKeyPath )
115
+ }
116
+
155
117
partdb , err := db .MakeErasableAccessor (partKeyPath )
156
118
if err != nil {
157
119
return
@@ -165,79 +127,15 @@ func (c *Client) GenParticipationKeysTo(address string, firstValid, lastValid, k
165
127
newPart , err := account .FillDBWithParticipationKeys (partdb , parsedAddr , firstRound , lastRound , keyDilution )
166
128
part = newPart .Participation
167
129
partdb .Close ()
168
- return part , partKeyPath , err
169
- }
170
-
171
- // InstallParticipationKeys creates a .partkey database for a given address,
172
- // based on an existing database from inputfile. On successful install, it
173
- // deletes the input file.
174
- func (c * Client ) InstallParticipationKeys (inputfile string ) (part account.Participation , filePath string , err error ) {
175
- proto , ok := c .consensus [protocol .ConsensusCurrentVersion ]
176
- if ! ok {
177
- err = fmt .Errorf ("Unknown consensus protocol %s" , protocol .ConsensusCurrentVersion )
178
- return
179
- }
180
-
181
- // Get the GenesisID for use in the participation key path
182
- var genID string
183
- genID , err = c .GenesisID ()
184
- if err != nil {
185
- return
186
- }
187
-
188
- outDir := filepath .Join (c .DataDir (), genID )
189
-
190
- inputdb , err := db .MakeErasableAccessor (inputfile )
191
- if err != nil {
192
- return
193
- }
194
- defer inputdb .Close ()
195
-
196
- partkey , err := account .RestoreParticipationWithSecrets (inputdb )
197
- if err != nil {
198
- return
199
- }
200
-
201
- if partkey .Parent == (basics.Address {}) {
202
- err = fmt .Errorf ("Cannot install partkey with missing (zero) parent address" )
203
- return
204
- }
205
-
206
- newdbpath , err := participationKeysPath (outDir , partkey .Parent , partkey .FirstValid , partkey .LastValid )
207
- if err != nil {
208
- return
209
- }
210
130
211
- newdb , err := db .MakeErasableAccessor (newdbpath )
212
131
if err != nil {
213
132
return
214
133
}
215
134
216
- newpartkey := partkey
217
- newpartkey .Store = newdb
218
- err = newpartkey .PersistWithSecrets ()
219
- if err != nil {
220
- newpartkey .Close ()
221
- return
135
+ if install {
136
+ _ , err = c .AddParticipationKey (partKeyPath )
222
137
}
223
-
224
- // After successful install, remove the input copy of the
225
- // partkey so that old keys cannot be recovered after they
226
- // are used by algod. We try to delete the data inside
227
- // sqlite first, so the key material is zeroed out from
228
- // disk blocks, but regardless of whether that works, we
229
- // delete the input file. The consensus protocol version
230
- // is irrelevant for the maxuint64 round number we pass in.
231
- errCh := partkey .DeleteOldKeys (basics .Round (math .MaxUint64 ), proto )
232
- err = <- errCh
233
- if err != nil {
234
- newpartkey .Close ()
235
- return
236
- }
237
- os .Remove (inputfile )
238
- part = newpartkey .Participation
239
- newpartkey .Close ()
240
- return part , newdbpath , nil
138
+ return part , partKeyPath , err
241
139
}
242
140
243
141
// ListParticipationKeys returns the available participation keys,
@@ -249,49 +147,3 @@ func (c *Client) ListParticipationKeys() (partKeyFiles generated.ParticipationKe
249
147
}
250
148
return
251
149
}
252
-
253
- // ListParticipationKeyFiles returns the available participation keys,
254
- // as a map from database filename to Participation key object.
255
- func (c * Client ) ListParticipationKeyFiles () (partKeyFiles map [string ]account.Participation , err error ) {
256
- genID , err := c .GenesisID ()
257
- if err != nil {
258
- return
259
- }
260
-
261
- // Get a list of files in the participation keys directory
262
- keyDir := filepath .Join (c .DataDir (), genID )
263
- files , err := ioutil .ReadDir (keyDir )
264
- if err != nil {
265
- return
266
- }
267
-
268
- partKeyFiles = make (map [string ]account.Participation )
269
- for _ , file := range files {
270
- // If it can't be a participation key database, skip it
271
- if ! config .IsPartKeyFilename (file .Name ()) {
272
- continue
273
- }
274
-
275
- filename := file .Name ()
276
-
277
- // Fetch a handle to this database
278
- handle , err := db .MakeErasableAccessor (filepath .Join (keyDir , filename ))
279
- if err != nil {
280
- // Couldn't open it, skip it
281
- continue
282
- }
283
-
284
- // Fetch an account.Participation from the database
285
- part , err := account .RestoreParticipation (handle )
286
- if err != nil {
287
- // Couldn't read it, skip it
288
- handle .Close ()
289
- continue
290
- }
291
-
292
- partKeyFiles [filename ] = part .Participation
293
- part .Close ()
294
- }
295
-
296
- return
297
- }
0 commit comments