Skip to content

Commit 590dfff

Browse files
authored
Merge pull request #118 from dedis/adds-delete-election
Adds the functionality to delete an election
2 parents d431e0e + 521579e commit 590dfff

File tree

14 files changed

+329
-11
lines changed

14 files changed

+329
-11
lines changed

contracts/evoting/controller/action.go

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ func (a *RegisterAction) Execute(ctx node.Context) error {
164164
router.HandleFunc("/evoting/elections/{electionID}", ep.Election).Methods("GET")
165165
router.HandleFunc("/evoting/elections/{electionID}", ep.EditElection).Methods("PUT")
166166
router.HandleFunc("/evoting/elections/{electionID}", eproxy.AllowCORS).Methods("OPTIONS")
167+
router.HandleFunc("/evoting/elections/{electionID}", ep.DeleteElection).Methods("DELETE")
167168
router.HandleFunc("/evoting/elections/{electionID}/vote", ep.NewElectionVote).Methods("POST")
168169

169170
router.NotFoundHandler = http.HandlerFunc(eproxy.NotFoundHandler)

contracts/evoting/evoting.go

+56
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/evoting/json/transaction.go

+17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package json
22

33
import (
44
"encoding/json"
5+
56
"github.com/dedis/d-voting/contracts/evoting/types"
67
"go.dedis.ch/dela/serde"
78
"golang.org/x/xerrors"
@@ -111,6 +112,12 @@ func (transactionFormat) Encode(ctx serde.Context, msg serde.Message) ([]byte, e
111112
}
112113

113114
m = TransactionJSON{CancelElection: &ce}
115+
case types.DeleteElection:
116+
de := DeleteElectionJSON{
117+
ElectionID: t.ElectionID,
118+
}
119+
120+
m = TransactionJSON{DeleteElection: &de}
114121
default:
115122
return nil, xerrors.Errorf("unknown type: '%T", msg)
116123
}
@@ -178,6 +185,10 @@ func (transactionFormat) Decode(ctx serde.Context, data []byte) (serde.Message,
178185
ElectionID: m.CancelElection.ElectionID,
179186
UserID: m.CancelElection.UserID,
180187
}, nil
188+
case m.DeleteElection != nil:
189+
return types.DeleteElection{
190+
ElectionID: m.DeleteElection.ElectionID,
191+
}, nil
181192
}
182193

183194
return nil, xerrors.Errorf("empty type: %s", data)
@@ -194,6 +205,7 @@ type TransactionJSON struct {
194205
RegisterPubShares *RegisterPubSharesJSON `json:",omitempty"`
195206
CombineShares *CombineSharesJSON `json:",omitempty"`
196207
CancelElection *CancelElectionJSON `json:",omitempty"`
208+
DeleteElection *DeleteElectionJSON `json:",omitempty"`
197209
}
198210

199211
// CreateElectionJSON is the JSON representation of a CreateElection transaction
@@ -251,6 +263,11 @@ type CancelElectionJSON struct {
251263
UserID string
252264
}
253265

266+
// DeleteElectionJSON is the JSON representation of a DeleteElection transaction
267+
type DeleteElectionJSON struct {
268+
ElectionID string
269+
}
270+
254271
func decodeCastVote(ctx serde.Context, m CastVoteJSON) (serde.Message, error) {
255272
factory := ctx.GetFactory(types.CiphervoteKey{})
256273
if factory == nil {

contracts/evoting/mod.go

+10
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type commands interface {
5555
registerPubshares(snap store.Snapshot, step execution.Step) error
5656
combineShares(snap store.Snapshot, step execution.Step) error
5757
cancelElection(snap store.Snapshot, step execution.Step) error
58+
deleteElection(snap store.Snapshot, step execution.Step) error
5859
}
5960

6061
// Command defines a type of command for the value contract
@@ -72,12 +73,16 @@ const (
7273
// CmdShuffleBallots is the command to shuffle ballots
7374
CmdShuffleBallots Command = "SHUFFLE_BALLOTS"
7475

76+
// CmdRegisterPubShares is the command to register the pubshares
7577
CmdRegisterPubShares Command = "REGISTER_PUB_SHARES"
7678

7779
// CmdCombineShares is the command to decrypt ballots
7880
CmdCombineShares Command = "COMBINE_SHARES"
7981
// CmdCancelElection is the command to cancel an election
8082
CmdCancelElection Command = "CANCEL_ELECTION"
83+
84+
// CmdDeleteElection is the command to delete an election
85+
CmdDeleteElection Command = "DELETE_ELECTION"
8186
)
8287

8388
// NewCreds creates new credentials for a evoting contract execution. We might
@@ -200,6 +205,11 @@ func (c Contract) Execute(snap store.Snapshot, step execution.Step) error {
200205
if err != nil {
201206
return xerrors.Errorf("failed to cancel election: %v", err)
202207
}
208+
case CmdDeleteElection:
209+
err := c.cmd.deleteElection(snap, step)
210+
if err != nil {
211+
return xerrors.Errorf("failed to delete election: %v", err)
212+
}
203213
default:
204214
return xerrors.Errorf("unknown command: %s", cmd)
205215
}

contracts/evoting/mod_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,10 @@ func (c fakeCmd) cancelElection(snap store.Snapshot, step execution.Step) error
13461346
return c.err
13471347
}
13481348

1349+
func (c fakeCmd) deleteElection(snap store.Snapshot, step execution.Step) error {
1350+
return c.err
1351+
}
1352+
13491353
func (c fakeCmd) registerPubshares(snap store.Snapshot, step execution.Step) error {
13501354
return c.err
13511355
}

contracts/evoting/types/transactions.go

+34-6
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,20 @@ type ElectionsMetadata struct {
2929
// ElectionIDs is a slice of hex-encoded election IDs
3030
type ElectionIDs []string
3131

32-
// Contains checks if el is present
33-
func (e ElectionIDs) Contains(el string) bool {
34-
for _, e1 := range e {
32+
// Contains checks if el is present. Return < 0 if not.
33+
func (e ElectionIDs) Contains(el string) int {
34+
for i, e1 := range e {
3535
if e1 == el {
36-
return true
36+
return i
3737
}
3838
}
3939

40-
return false
40+
return -1
4141
}
4242

4343
// Add adds an election ID or returns an error if already present
4444
func (e *ElectionIDs) Add(id string) error {
45-
if e.Contains(id) {
45+
if e.Contains(id) >= 0 {
4646
return xerrors.Errorf("id %q already exist", id)
4747
}
4848

@@ -51,6 +51,14 @@ func (e *ElectionIDs) Add(id string) error {
5151
return nil
5252
}
5353

54+
// Remove removes an election ID from the list, if it exists
55+
func (e *ElectionIDs) Remove(id string) {
56+
i := e.Contains(id)
57+
if i >= 0 {
58+
*e = append((*e)[:i], (*e)[i+1:]...)
59+
}
60+
}
61+
5462
// TransactionFactory provides the mean to deserialize a transaction.
5563
//
5664
// - implements serde.Factory
@@ -267,6 +275,26 @@ func (ce CancelElection) Serialize(ctx serde.Context) ([]byte, error) {
267275
return data, nil
268276
}
269277

278+
// DeleteElection defines the transaction to delete the election
279+
//
280+
// - implements serde.Message
281+
type DeleteElection struct {
282+
// ElectionID is hex-encoded
283+
ElectionID string
284+
}
285+
286+
// Serialize implements serde.Message
287+
func (ce DeleteElection) Serialize(ctx serde.Context) ([]byte, error) {
288+
format := transactionFormats.Get(ctx.GetFormat())
289+
290+
data, err := format.Encode(ctx, ce)
291+
if err != nil {
292+
return nil, xerrors.Errorf("failed to encode cancel election: %v", err)
293+
}
294+
295+
return data, nil
296+
}
297+
270298
// RandomID returns the hex encoding of a randomly created 32 byte ID.
271299
func RandomID() (string, error) {
272300
buf := make([]byte, 32)

docs/api.md

+26
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ SC6:CombineShares
5656
5757
SC2:ElectionGetInfo
5858
59+
60+
5961
```
6062

6163
In case of error:
@@ -267,6 +269,30 @@ Return:
267269
268270
```
269271

272+
# SC?: Election delete
273+
274+
| | |
275+
| ------- | --------------------------------- |
276+
| URL | `/evoting/elections/{ElectionID}` |
277+
| Method | `DELETE` |
278+
| Input | |
279+
| Headers | {Authorization: <token>} |
280+
281+
The <token> value must be the hex-encoded signature of the hex-encoded
282+
electionID:
283+
284+
```
285+
<token> = hex( sig( hex( electionID ) ) )
286+
```
287+
288+
Return:
289+
290+
`200 OK` `text/plain`
291+
292+
```
293+
294+
```
295+
270296
# SC?: Election get all infos
271297

272298
| | |

proxy/election.go

+63-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"go.dedis.ch/dela/core/txn/pool"
2323
"go.dedis.ch/dela/serde"
2424
"go.dedis.ch/kyber/v3"
25+
"go.dedis.ch/kyber/v3/sign/schnorr"
2526
"golang.org/x/xerrors"
2627
)
2728

@@ -147,7 +148,7 @@ func (h *election) NewElectionVote(w http.ResponseWriter, r *http.Request) {
147148
return
148149
}
149150

150-
if !elecMD.ElectionsIDs.Contains(electionID) {
151+
if elecMD.ElectionsIDs.Contains(electionID) < 0 {
151152
http.Error(w, "the election does not exist", http.StatusNotFound)
152153
return
153154
}
@@ -214,7 +215,7 @@ func (h *election) EditElection(w http.ResponseWriter, r *http.Request) {
214215
return
215216
}
216217

217-
if !elecMD.ElectionsIDs.Contains(electionID) {
218+
if elecMD.ElectionsIDs.Contains(electionID) < 0 {
218219
http.Error(w, "the election does not exist", http.StatusNotFound)
219220
return
220221
}
@@ -453,6 +454,61 @@ func (h *election) Elections(w http.ResponseWriter, r *http.Request) {
453454
}
454455
}
455456

457+
// DeleteElection implements proxy.Proxy
458+
func (h *election) DeleteElection(w http.ResponseWriter, r *http.Request) {
459+
vars := mux.Vars(r)
460+
461+
if vars == nil || vars["electionID"] == "" {
462+
http.Error(w, fmt.Sprintf("electionID not found: %v", vars), http.StatusInternalServerError)
463+
return
464+
}
465+
466+
electionID := vars["electionID"]
467+
468+
elecMD, err := h.getElectionsMetadata()
469+
if err != nil {
470+
http.Error(w, "failed to get election metadata", http.StatusNotFound)
471+
return
472+
}
473+
474+
if elecMD.ElectionsIDs.Contains(electionID) < 0 {
475+
http.Error(w, "the election does not exist", http.StatusNotFound)
476+
return
477+
}
478+
479+
// auth should contain the hex-encoded signature on the hex-encoded election
480+
// ID
481+
auth := r.Header.Get("Authorization")
482+
483+
sig, err := hex.DecodeString(auth)
484+
if err != nil {
485+
BadRequestError(w, r, xerrors.Errorf("failed to decode auth: %v", err), nil)
486+
return
487+
}
488+
489+
err = schnorr.Verify(suite, h.pk, []byte(electionID), sig)
490+
if err != nil {
491+
ForbiddenError(w, r, xerrors.Errorf("signature verification failed: %v", err), nil)
492+
return
493+
}
494+
495+
deleteElection := types.DeleteElection{
496+
ElectionID: electionID,
497+
}
498+
499+
data, err := deleteElection.Serialize(h.context)
500+
if err != nil {
501+
InternalError(w, r, xerrors.Errorf("failed to marshal DeleteElection: %v", err), nil)
502+
return
503+
}
504+
505+
_, err = h.submitAndWaitForTxn(r.Context(), evoting.CmdDeleteElection, evoting.ElectionArg, data)
506+
if err != nil {
507+
http.Error(w, "failed to submit txn: "+err.Error(), http.StatusInternalServerError)
508+
return
509+
}
510+
}
511+
456512
// waitForTxnID blocks until `ID` is included or `events` is closed.
457513
func (h *election) waitForTxnID(events <-chan ordering.Event, ID []byte) error {
458514
for event := range events {
@@ -483,6 +539,11 @@ func (h *election) getElectionsMetadata() (types.ElectionsMetadata, error) {
483539
return md, nil
484540
}
485541

542+
// if there is not election created yet the metadata will be empty
543+
if len(proof.GetValue()) == 0 {
544+
return types.ElectionsMetadata{}, nil
545+
}
546+
486547
err = json.Unmarshal(proof.GetValue(), &md)
487548
if err != nil {
488549
return md, xerrors.Errorf("failed to unmarshal ElectionMetadata: %v", err)

0 commit comments

Comments
 (0)