protocol.go 4.6 KB
Newer Older
1
2
3
4
package sign

import (
	"fmt"
Richer Maximilien's avatar
Richer Maximilien committed
5
	"log"
6
7
8

	cAPI "dfss/dfssc/api"
	"dfss/dfssc/common"
Richer Maximilien's avatar
Richer Maximilien committed
9
	dAPI "dfss/dfssd/api"
10
11
)

12
13
14
15
16
17
18
// Sign performe all the message exchange for the contract to be signed
//
// * Initialize the SignatureManager from starter.go
// * Compute the reversed map [mail -> ID] of signers
// * Make channels for handlers
// * Promises rounds
// * Signature round
19
func (m *SignatureManager) Sign() error {
20
21

	myID, nextIndex, err := m.Initialize()
22
23
24
25
	if err != nil {
		return err
	}

26
	m.makeSignersHashToIDMap()
27

28
29
	m.cServerIface.incomingPromises = make(chan *cAPI.Promise)
	m.cServerIface.incomingSignatures = make(chan *cAPI.Signature)
30

31
	// Promess rounds
32
	// Follow the sequence until there is no next occurence of me
33
	for m.currentIndex >= 0 {
34

35
		dAPI.DLog(fmt.Sprintf("{%d} ", myID) + "Starting round at index [" + fmt.Sprintf("%d", m.currentIndex) + "] with nextIndex=" + fmt.Sprintf("%d", nextIndex))
Richer Maximilien's avatar
Richer Maximilien committed
36

37
38
		// Set of the promise we are waiting for
		pendingSet, err1 := common.GetPendingSet(m.sequence, myID, m.currentIndex)
39
40
		if err1 != nil {
			return err1 // err is renamed to avoid shadowing err on linter check
41
42
		}

43
44
		// Set of the promises we must send
		sendSet, err1 := common.GetSendSet(m.sequence, myID, m.currentIndex)
45
46
		if err1 != nil {
			return err1
47
48
		}

49
50
		// Exchange messages
		m.promiseRound(pendingSet, sendSet, myID)
51

52
53
		m.currentIndex = nextIndex
		nextIndex, err1 = common.FindNextIndex(m.sequence, myID, m.currentIndex)
54
55
		if err1 != nil {
			return err1
56
57
58
		}
	}

59
60
	dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Enter signature round")

61
62
63
64
65
	// Signature round
	err = m.SendAllSigns()
	if err != nil {
		return err
	}
66
67

	dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Exit signature round")
68

69
70
71
72
73
74
75
	// Network's job is done, cleaning time
	// Shutdown and platform client and TODO peer server & connections
	err = m.platformConn.Close()
	if err != nil {
		return err
	}

76
77
78
79
80
81
82
83
84
85
86
87
88
89
	return nil
}

// GetClient retrieves the Client to the specified sequence id provided it exists
func (m *SignatureManager) GetClient(to uint32) (*cAPI.ClientClient, error) {
	mailto := m.contract.Signers[to].Email

	if _, ok := m.peers[mailto]; !ok {
		return nil, fmt.Errorf("No connection to user %s", mailto)
	}

	return m.peers[mailto], nil
}

90
// makeEMailMap build an association to reverse a hash to the sequence ID
91
func (m *SignatureManager) makeSignersHashToIDMap() {
92

93
	m.hashToID = make(map[string]uint32)
94

95
96
	signers := m.contract.Signers
	for id, signer := range signers {
97
		m.hashToID[signer.Hash] = uint32(id)
98
99
100
	}
}

101
102
103
// promiseRound describe a promise round: reception and sending
//
// TODO better error management - this function should return `error` !
104
105
106
107
108
func (m *SignatureManager) promiseRound(pendingSet, sendSet []uint32, myID uint32) {

	// Reception of the due promises
	// TODO this ctx needs a timeout !
	for len(pendingSet) > 0 {
109
110
		promise := <-m.cServerIface.incomingPromises
		senderID, exist := m.hashToID[fmt.Sprintf("%x", promise.SenderKeyHash)]
111
112
113
114
		if exist {
			var err error
			pendingSet, err = common.Remove(pendingSet, senderID)
			if err != nil {
115
				_ = fmt.Errorf("Recieve unexpected promise")
116
117
			}
			m.archives.recievedPromises = append(m.archives.recievedPromises, promise)
118
			dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Recieved promise from [" + fmt.Sprintf("%d", senderID) + "] for index " + fmt.Sprintf("%d", promise.Index))
119
120
		} else {
			// Wrong sender keyHash
121
			log.Println("{" + fmt.Sprintf("%d", myID) + "} Wrong sender keyhash !")
122
		}
123
124
	}

125
126
127
128
129
130
131
	c := make(chan *cAPI.Promise)
	// Sending of due promises
	for _, id := range sendSet {
		// The signature manager is read only - safe !
		go func(id uint32, m *SignatureManager) {
			promise, err := m.CreatePromise(myID, id)
			if err != nil {
132
				_ = fmt.Errorf("Failed to create promise from %d to %d", myID, id)
133
			}
134
			dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Send promise to " + fmt.Sprintf("%d", id))
135
136
			_, err = m.SendPromise(promise, id)
			if err != nil {
137
138
				dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Promise have not been recieved !")
				_ = fmt.Errorf("Failed to deliver promise from %d to %d", myID, id)
139
140
141
			}
			c <- promise
		}(id, m)
142
143
	}

144
145
146
147
148
149
150
151
	// Verifying we sent all the due promesses
	for _ = range sendSet {
		promise := <-c
		if promise != nil {
			m.archives.sentPromises = append(m.archives.sentPromises, promise)
		} else {
			// something appened during the goroutine
		}
152
153
	}
}
154
155
156
157
158
159
160
161
162
163
164
165
166

// closeAllPeerClient tries to close all established connection with other peers
func (m *SignatureManager) closeAllPeerClient() {
	for k, client := range m.peersConn {
		err := client.Close()
		if err != nil {
			// We don't care
		}
		// Remove associated grpc client
		delete(m.peers, k)
		fmt.Println("- Close connection to " + k)
	}
}