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

import (
	"fmt"
5
	"time"
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 performs 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
	myID, nextIndex, err := m.Initialize()
21
22
23
24
	if err != nil {
		return err
	}

25
	m.makeSignersHashToIDMap()
26
27
	m.cServerIface.incomingPromises = make(chan interface{})
	m.cServerIface.incomingSignatures = make(chan interface{})
28

29
30
	// Cooldown delay, let other clients wake-up their channels
	time.Sleep(time.Second)
31

32
	// Promess rounds
33
	// Follow the sequence until there is no next occurence of me
34
	for m.currentIndex >= 0 {
35
		dAPI.DLog("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
	dAPI.DLog("entering signature round")
62
	// Signature round
63
	err = m.ExchangeAllSignatures()
64
65
66
	if err != nil {
		return err
	}
67
	dAPI.DLog("exiting signature round")
68

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

// GetClient retrieves the Client to the specified sequence id provided it exists
75
76
77
78
func (m *SignatureManager) GetClient(to uint32) (client *cAPI.ClientClient, mail string) {
	mail = m.contract.Signers[to].Email
	client = m.peers[mail]
	return
79
80
}

81
// makeSignersHashToIDMap builds an association to reverse a hash to the sequence ID
82
83
func (m *SignatureManager) makeSignersHashToIDMap() {
	m.hashToID = make(map[string]uint32)
84
85
	signers := m.contract.Signers
	for id, signer := range signers {
86
		m.hashToID[signer.Hash] = uint32(id)
87
88
89
	}
}

90
// promiseRound describes a promise round: reception and sending
91
// TODO better error management - this function should return `error` !
92
93
94
95
96
func (m *SignatureManager) promiseRound(pendingSet, sendSet []uint32, myID uint32) {

	// Reception of the due promises
	// TODO this ctx needs a timeout !
	for len(pendingSet) > 0 {
97
98
		promise := (<-m.cServerIface.incomingPromises).(*cAPI.Promise)
		senderID, exist := m.hashToID[fmt.Sprintf("%x", promise.Context.SenderKeyHash)]
99
100
101
102
		if exist {
			var err error
			pendingSet, err = common.Remove(pendingSet, senderID)
			if err != nil {
103
				continue
104
			}
105
			m.archives.receivedPromises = append(m.archives.receivedPromises, promise)
106
		}
107
108
	}

109
110
111
112
113
	c := make(chan *cAPI.Promise)
	// Sending of due promises
	for _, id := range sendSet {
		go func(id uint32, m *SignatureManager) {
			promise, err := m.CreatePromise(myID, id)
114
115
			if err == nil {
				_ = m.SendEvidence(promise, nil, id)
116
117
118
			}
			c <- promise
		}(id, m)
119
120
	}

121
	// Verifying we sent all the due promises
122
123
	for range sendSet {
		_ = <-c
124
125
	}
}
126
127
128
129

// closeAllPeerClient tries to close all established connection with other peers
func (m *SignatureManager) closeAllPeerClient() {
	for k, client := range m.peersConn {
130
		_ = client.Close()
131
132
133
134
		// Remove associated grpc client
		delete(m.peers, k)
	}
}