protocol.go 4.55 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
// Sign perform all the message exchanges for the contract to be signed
13
14
15
16
17
18
//
// * 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
		// Set of the promise we are waiting for
38
39
40
41
		var pendingSet []uint32
		pendingSet, err = common.GetPendingSet(m.sequence, myID, m.currentIndex)
		if err != nil {
			return err
42
43
		}

44
		// Set of the promises we must send
45
46
47
48
		var sendSet []uint32
		sendSet, err = common.GetSendSet(m.sequence, myID, m.currentIndex)
		if err != nil {
			return err
49
50
		}

51
52
		// Exchange messages
		m.promiseRound(pendingSet, sendSet, myID)
53

54
		m.currentIndex = nextIndex
55
56
57
		nextIndex, err = common.FindNextIndex(m.sequence, myID, m.currentIndex)
		if err != nil {
			return err
58
59
60
		}
	}

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

63
	// Signature round
64
	err = m.ExchangeAllSignatures()
65
66
67
	if err != nil {
		return err
	}
68
69

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

71
72
73
74
75
76
77
	// 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
	}

78
79
80
81
82
83
84
85
86
87
88
89
90
91
	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
}

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

95
	m.hashToID = make(map[string]uint32)
96

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

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

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

127
128
129
130
131
132
133
	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 {
134
				_ = fmt.Errorf("Failed to create promise from %d to %d", myID, id)
135
			}
136
			dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Send promise to " + fmt.Sprintf("%d", id))
137
138
			_, err = m.SendPromise(promise, id)
			if err != nil {
139
				dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Promise have not been received !")
140
				_ = fmt.Errorf("Failed to deliver promise from %d to %d", myID, id)
141
142
143
			}
			c <- promise
		}(id, m)
144
145
	}

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

// closeAllPeerClient tries to close all established connection with other peers
func (m *SignatureManager) closeAllPeerClient() {
	for k, client := range m.peersConn {
160
		_ = client.Close()
161
162
163
164
165
		// Remove associated grpc client
		delete(m.peers, k)
		fmt.Println("- Close connection to " + k)
	}
}