protocol.go 4.1 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
76
77
78
79
80
81
82

	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
}

83
// makeEMailMap build an association to reverse a hash to the sequence ID
84
func (m *SignatureManager) makeSignersHashToIDMap() {
85

86
	m.hashToID = make(map[string]uint32)
87

88
89
	signers := m.contract.Signers
	for id, signer := range signers {
90
		m.hashToID[signer.Hash] = uint32(id)
91
92
93
	}
}

94
95
96
// promiseRound describe a promise round: reception and sending
//
// TODO better error management - this function should return `error` !
97
98
99
100
101
func (m *SignatureManager) promiseRound(pendingSet, sendSet []uint32, myID uint32) {

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

118
119
120
121
122
123
124
	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 {
125
				_ = fmt.Errorf("Failed to create promise from %d to %d", myID, id)
126
			}
127
			dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Send promise to " + fmt.Sprintf("%d", id))
128
129
			_, err = m.SendPromise(promise, id)
			if err != nil {
130
131
				dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Promise have not been recieved !")
				_ = fmt.Errorf("Failed to deliver promise from %d to %d", myID, id)
132
133
134
			}
			c <- promise
		}(id, m)
135
136
	}

137
138
139
140
141
142
143
144
	// 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
		}
145
146
	}
}