protocol.go 4.08 KB
Newer Older
1
// Package sign handles contract and signature operations.
2 3 4 5
package sign

import (
	"fmt"
Loïck Bonniot's avatar
Loïck Bonniot committed
6
	"os"
7
	"time"
8 9 10

	cAPI "dfss/dfssc/api"
	"dfss/dfssc/common"
Richer Maximilien's avatar
Richer Maximilien committed
11
	dAPI "dfss/dfssd/api"
Loïck Bonniot's avatar
Loïck Bonniot committed
12
	"github.com/spf13/viper"
13 14
)

15
// Sign performs all the message exchanges for the contract to be signed
16 17 18 19 20 21
//
// * Initialize the SignatureManager from starter.go
// * Compute the reversed map [mail -> ID] of signers
// * Make channels for handlers
// * Promises rounds
// * Signature round
22
func (m *SignatureManager) Sign() error {
23 24 25 26 27 28

	defer func() {
		m.finished = true
		m.closeConnections()
	}()

29
	myID, nextIndex, err := m.Initialize()
30 31 32 33
	if err != nil {
		return err
	}

34
	m.makeSignersHashToIDMap()
35 36
	m.cServerIface.incomingPromises = make(chan interface{}, chanBufferSize)
	m.cServerIface.incomingSignatures = make(chan interface{}, chanBufferSize)
37

38 39
	// Cooldown delay, let other clients wake-up their channels
	time.Sleep(time.Second)
40

Loïck Bonniot's avatar
Loïck Bonniot committed
41 42
	seqLen := len(m.sequence)

43
	// Promess rounds
44
	// Follow the sequence until there is no next occurence of me
45
	for m.currentIndex >= 0 {
Loïck Bonniot's avatar
Loïck Bonniot committed
46
		stopIfNeeded(m.currentIndex)
Loïck Bonniot's avatar
Loïck Bonniot committed
47
		m.OnProgressUpdate(m.currentIndex, seqLen+1)
Loïck Bonniot's avatar
Loïck Bonniot committed
48
		time.Sleep(viper.GetDuration("slowdown"))
49
		dAPI.DLog("starting round at index [" + fmt.Sprintf("%d", m.currentIndex) + "] with nextIndex=" + fmt.Sprintf("%d", nextIndex))
Richer Maximilien's avatar
Richer Maximilien committed
50

Loïck Bonniot's avatar
Loïck Bonniot committed
51
		// Set of promises we are waiting for
52 53 54 55
		var pendingSet []uint32
		pendingSet, err = common.GetPendingSet(m.sequence, myID, m.currentIndex)
		if err != nil {
			return err
56 57
		}

58
		// Set of the promises we must send
59 60 61 62
		var sendSet []uint32
		sendSet, err = common.GetSendSet(m.sequence, myID, m.currentIndex)
		if err != nil {
			return err
63 64
		}

65 66
		// Exchange messages
		m.promiseRound(pendingSet, sendSet, myID)
67

68
		m.currentIndex = nextIndex
69 70 71
		nextIndex, err = common.FindNextIndex(m.sequence, myID, m.currentIndex)
		if err != nil {
			return err
72 73 74
		}
	}

Loïck Bonniot's avatar
Loïck Bonniot committed
75 76
	// Signature round
	stopIfNeeded(-1)
Loïck Bonniot's avatar
Loïck Bonniot committed
77
	m.OnProgressUpdate(seqLen, seqLen+1)
78
	dAPI.DLog("entering signature round")
79
	err = m.ExchangeAllSignatures()
80 81 82
	if err != nil {
		return err
	}
Loïck Bonniot's avatar
Loïck Bonniot committed
83

84
	dAPI.DLog("exiting signature round")
Loïck Bonniot's avatar
Loïck Bonniot committed
85
	m.OnProgressUpdate(seqLen+1, seqLen+1)
86
	return nil
87 88 89
}

// GetClient retrieves the Client to the specified sequence id provided it exists
90 91 92 93
func (m *SignatureManager) GetClient(to uint32) (client *cAPI.ClientClient, mail string) {
	mail = m.contract.Signers[to].Email
	client = m.peers[mail]
	return
94 95
}

96
// makeSignersHashToIDMap builds an association to reverse a hash to the sequence ID
97 98
func (m *SignatureManager) makeSignersHashToIDMap() {
	m.hashToID = make(map[string]uint32)
99 100
	signers := m.contract.Signers
	for id, signer := range signers {
101
		m.hashToID[signer.Hash] = uint32(id)
102 103 104
	}
}

105
// promiseRound describes a promise round: reception and sending
106 107 108 109
func (m *SignatureManager) promiseRound(pendingSet, sendSet []uint32, myID uint32) {

	// Reception of the due promises
	for len(pendingSet) > 0 {
110 111 112 113 114 115 116 117 118 119 120
		select {
		case promiseIface := <-m.cServerIface.incomingPromises:
			promise := (promiseIface).(*cAPI.Promise)
			senderID, exist := m.hashToID[fmt.Sprintf("%x", promise.Context.SenderKeyHash)]
			if exist {
				var err error
				pendingSet, err = common.Remove(pendingSet, senderID)
				if err != nil {
					continue
				}
				m.archives.receivedPromises = append(m.archives.receivedPromises, promise)
121
			}
122 123 124 125

		case <-time.After(time.Minute):
			// TODO contact TTP
			return
126
		}
127 128
	}

129
	c := make(chan *cAPI.Promise, chanBufferSize)
130 131 132 133
	// Sending of due promises
	for _, id := range sendSet {
		go func(id uint32, m *SignatureManager) {
			promise, err := m.CreatePromise(myID, id)
134 135
			if err == nil {
				_ = m.SendEvidence(promise, nil, id)
136 137 138
			}
			c <- promise
		}(id, m)
139 140
	}

141
	// Verifying we sent all the due promises
142
	for range sendSet {
Loïck Bonniot's avatar
Loïck Bonniot committed
143
		<-c
144 145
	}
}
146

147 148 149 150 151 152
// closeConnections tries to close all established connection with other peers and platform.
// It also stops the local server.
func (m *SignatureManager) closeConnections() {
	_ = m.platformConn.Close()
	for k, peer := range m.peersConn {
		_ = peer.Close()
153 154
		delete(m.peers, k)
	}
155
	m.cServer.Stop()
156
}
Loïck Bonniot's avatar
Loïck Bonniot committed
157 158 159 160 161 162 163 164 165 166 167

func stopIfNeeded(index int) {
	s := viper.GetInt("stopbefore")
	if s == 0 {
		return
	}

	if index == -1 && s == -1 || index+1 == s {
		os.Exit(0)
	}
}