Commit 5bb03e5d authored by Loïck Bonniot's avatar Loïck Bonniot

[c] Improve signature style and fix crashes

- Factorizes code between promises and signatures
- Add a cooldown before starting the first round
- Add demonstrator trace in integration tests
parent c8e658a4
......@@ -9,6 +9,7 @@ It is generated from these files:
dfss/dfssc/api/client.proto
It has these top-level messages:
Context
Promise
Signature
Hello
......@@ -34,39 +35,57 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
const _ = proto.ProtoPackageIsVersion1
type Context struct {
RecipientKeyHash []byte `protobuf:"bytes,1,opt,name=recipientKeyHash,proto3" json:"recipientKeyHash,omitempty"`
SenderKeyHash []byte `protobuf:"bytes,2,opt,name=senderKeyHash,proto3" json:"senderKeyHash,omitempty"`
SignatureUuid string `protobuf:"bytes,3,opt,name=signatureUuid" json:"signatureUuid,omitempty"`
ContractUuid string `protobuf:"bytes,4,opt,name=contractUuid" json:"contractUuid,omitempty"`
ContractDocumentHash string `protobuf:"bytes,5,opt,name=contractDocumentHash" json:"contractDocumentHash,omitempty"`
}
func (m *Context) Reset() { *m = Context{} }
func (m *Context) String() string { return proto.CompactTextString(m) }
func (*Context) ProtoMessage() {}
func (*Context) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
// Promise message contains all the required information to verify
// the identity of the sender and receiver, and the actual promise
//
// * sequence is transmitted by platform and identical across clients
// * TODO implement an global signature for content
type Promise struct {
RecipientKeyHash []byte `protobuf:"bytes,1,opt,name=recipientKeyHash,proto3" json:"recipientKeyHash,omitempty"`
SenderKeyHash []byte `protobuf:"bytes,2,opt,name=senderKeyHash,proto3" json:"senderKeyHash,omitempty"`
Index uint32 `protobuf:"varint,3,opt,name=index" json:"index,omitempty"`
ContractDocumentHash string `protobuf:"bytes,4,opt,name=contractDocumentHash" json:"contractDocumentHash,omitempty"`
SignatureUuid string `protobuf:"bytes,5,opt,name=signatureUuid" json:"signatureUuid,omitempty"`
ContractUuid string `protobuf:"bytes,6,opt,name=contractUuid" json:"contractUuid,omitempty"`
Context *Context `protobuf:"bytes,1,opt,name=context" json:"context,omitempty"`
Index uint32 `protobuf:"varint,2,opt,name=index" json:"index,omitempty"`
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
}
func (m *Promise) Reset() { *m = Promise{} }
func (m *Promise) String() string { return proto.CompactTextString(m) }
func (*Promise) ProtoMessage() {}
func (*Promise) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (*Promise) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *Promise) GetContext() *Context {
if m != nil {
return m.Context
}
return nil
}
// Signature message contains all the required information to verify
// the identity of the sender and receiver, and the actual signature
type Signature struct {
RecipientKeyHash []byte `protobuf:"bytes,1,opt,name=recipientKeyHash,proto3" json:"recipientKeyHash,omitempty"`
SenderKeyHash []byte `protobuf:"bytes,2,opt,name=senderKeyHash,proto3" json:"senderKeyHash,omitempty"`
Signature string `protobuf:"bytes,3,opt,name=signature" json:"signature,omitempty"`
SignatureUuid string `protobuf:"bytes,4,opt,name=signatureUuid" json:"signatureUuid,omitempty"`
ContractUuid string `protobuf:"bytes,5,opt,name=contractUuid" json:"contractUuid,omitempty"`
Context *Context `protobuf:"bytes,1,opt,name=context" json:"context,omitempty"`
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
}
func (m *Signature) Reset() { *m = Signature{} }
func (m *Signature) String() string { return proto.CompactTextString(m) }
func (*Signature) ProtoMessage() {}
func (*Signature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (*Signature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *Signature) GetContext() *Context {
if m != nil {
return m.Context
}
return nil
}
// Hello message is used when discovering peers.
// It contains the current version of the software.
......@@ -77,9 +96,10 @@ type Hello struct {
func (m *Hello) Reset() { *m = Hello{} }
func (m *Hello) String() string { return proto.CompactTextString(m) }
func (*Hello) ProtoMessage() {}
func (*Hello) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (*Hello) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func init() {
proto.RegisterType((*Context)(nil), "api.Context")
proto.RegisterType((*Promise)(nil), "api.Promise")
proto.RegisterType((*Signature)(nil), "api.Signature")
proto.RegisterType((*Hello)(nil), "api.Hello")
......@@ -205,24 +225,27 @@ var _Client_serviceDesc = grpc.ServiceDesc{
}
var fileDescriptor0 = []byte{
// 303 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x51, 0xdd, 0x4a, 0xf4, 0x30,
0x10, 0xdd, 0x7e, 0xfb, 0xf7, 0x75, 0x68, 0x57, 0x0d, 0x2b, 0x94, 0xaa, 0x20, 0xc5, 0x0b, 0xaf,
0x5a, 0x58, 0x1f, 0x61, 0x57, 0x58, 0xf0, 0x46, 0x50, 0x1f, 0x20, 0xa6, 0x59, 0x0d, 0xb4, 0x4d,
0x99, 0xa4, 0xa2, 0xe0, 0x53, 0x88, 0x0f, 0x6c, 0x3a, 0x6b, 0xab, 0x17, 0xbd, 0xf1, 0x26, 0xe4,
0x9c, 0x39, 0x33, 0xe7, 0x64, 0x02, 0x27, 0xf9, 0xce, 0x98, 0xac, 0x3d, 0x44, 0xc6, 0x6b, 0x95,
0x89, 0x42, 0xc9, 0xca, 0xa6, 0x35, 0x6a, 0xab, 0xd9, 0xd8, 0x31, 0xf1, 0x59, 0xaf, 0xa8, 0x49,
0x51, 0x17, 0xdc, 0xee, 0x34, 0x96, 0x7b, 0x4d, 0xf2, 0xe9, 0xc1, 0xfc, 0x16, 0x75, 0xa9, 0x8c,
0x64, 0x11, 0x1c, 0xa2, 0x14, 0xaa, 0x6e, 0x47, 0xdc, 0xc8, 0xb7, 0x2d, 0x37, 0xcf, 0x91, 0x77,
0xee, 0x5d, 0x06, 0xec, 0x18, 0x42, 0x23, 0xab, 0x5c, 0x62, 0x47, 0xff, 0x23, 0x3a, 0x84, 0xa9,
0x72, 0xec, 0x6b, 0x34, 0x76, 0x30, 0x64, 0xa7, 0xb0, 0x14, 0xba, 0xb2, 0xc8, 0x85, 0xdd, 0x68,
0xd1, 0x94, 0x6e, 0x0c, 0x89, 0x27, 0xae, 0xea, 0xd3, 0x0c, 0xf5, 0x54, 0x71, 0xdb, 0xa0, 0x7c,
0x68, 0x54, 0x1e, 0x4d, 0x89, 0x5e, 0x42, 0xd0, 0x35, 0x11, 0x3b, 0x6b, 0xd9, 0xe4, 0x1d, 0xfc,
0xbb, 0x4e, 0xfc, 0xf7, 0x5c, 0x47, 0xe0, 0xf7, 0x56, 0x94, 0x6d, 0xc0, 0x7d, 0x32, 0xe8, 0x4e,
0x99, 0x92, 0x08, 0xa6, 0x5b, 0x59, 0x14, 0x9a, 0x1d, 0xc0, 0xfc, 0x45, 0xa2, 0x51, 0xba, 0x22,
0x43, 0x7f, 0xf5, 0xe1, 0xc1, 0x6c, 0x4d, 0x3b, 0x66, 0x29, 0x04, 0xf7, 0x28, 0xb9, 0xed, 0xb6,
0x17, 0xa4, 0x6e, 0xbd, 0xe9, 0x37, 0x8a, 0x17, 0x84, 0xae, 0x11, 0x35, 0xae, 0x75, 0x2e, 0x93,
0x11, 0x5b, 0xc1, 0x82, 0xf4, 0x3f, 0xef, 0xda, 0x6b, 0x7a, 0x3c, 0xd0, 0x73, 0x01, 0xff, 0x37,
0xca, 0x08, 0xed, 0x42, 0x30, 0xa0, 0x2a, 0xe5, 0x8a, 0x7f, 0xdd, 0x93, 0xd1, 0xe3, 0x8c, 0xbe,
0xf2, 0xea, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x2d, 0x9f, 0xc1, 0xc3, 0x0d, 0x02, 0x00, 0x00,
// 348 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x92, 0xd1, 0x4a, 0xfb, 0x30,
0x14, 0xc6, 0xd7, 0xed, 0xbf, 0xf5, 0xbf, 0x63, 0x37, 0x24, 0xec, 0x62, 0x4c, 0x04, 0x2d, 0x43,
0xc4, 0x8b, 0x0e, 0xe6, 0x23, 0x6c, 0xc2, 0x40, 0x04, 0xa9, 0xfa, 0x00, 0x31, 0xcd, 0x34, 0xd0,
0x35, 0x25, 0xc9, 0x64, 0x7b, 0x0d, 0xdf, 0xce, 0xb7, 0x31, 0x3d, 0x59, 0xe6, 0x8a, 0xbb, 0xf0,
0xa6, 0xf4, 0xfb, 0xce, 0xaf, 0xe7, 0x9c, 0x2f, 0x0d, 0x9c, 0x65, 0x4b, 0xad, 0x27, 0xd5, 0x83,
0x4d, 0x68, 0x29, 0x26, 0x2c, 0x17, 0xbc, 0x30, 0x49, 0xa9, 0xa4, 0x91, 0xa4, 0x65, 0x9d, 0xd1,
0xf9, 0x9e, 0x28, 0x91, 0x28, 0x73, 0x6a, 0x96, 0x52, 0xad, 0x1c, 0x13, 0x7f, 0x05, 0x10, 0xce,
0x64, 0x61, 0xf8, 0xc6, 0x90, 0x1b, 0x38, 0x55, 0x9c, 0x89, 0xb2, 0x6a, 0x71, 0xcf, 0xb7, 0x0b,
0xaa, 0xdf, 0x87, 0xc1, 0x45, 0x70, 0x1d, 0xa5, 0xbf, 0x7c, 0x32, 0x86, 0x9e, 0xe6, 0x45, 0xc6,
0x95, 0x07, 0x9b, 0x08, 0xd6, 0x4d, 0xa4, 0xc4, 0x5b, 0x41, 0xcd, 0x5a, 0xf1, 0x97, 0xb5, 0xc8,
0x86, 0x2d, 0x4b, 0x75, 0xd3, 0xba, 0x49, 0x62, 0x88, 0x98, 0x5d, 0x41, 0x51, 0x66, 0x10, 0xfa,
0x87, 0x50, 0xcd, 0x23, 0x53, 0x18, 0x78, 0x3d, 0x97, 0x6c, 0xbd, 0xb2, 0xab, 0xe0, 0xd8, 0x36,
0xb2, 0x47, 0x6b, 0x31, 0x85, 0xf0, 0x51, 0xc9, 0x95, 0xd0, 0x9c, 0x5c, 0x41, 0xc8, 0x5c, 0x4a,
0x4c, 0x74, 0x32, 0x8d, 0x12, 0x7b, 0x18, 0xc9, 0x2e, 0x79, 0xea, 0x8b, 0x64, 0x00, 0x6d, 0x61,
0x03, 0x6c, 0x30, 0x4e, 0x2f, 0x75, 0x82, 0x0c, 0x21, 0x2c, 0xe9, 0x36, 0x97, 0xd4, 0x05, 0x88,
0x52, 0x2f, 0xe3, 0x07, 0xe8, 0x3e, 0xf9, 0x2c, 0x7f, 0x1e, 0x72, 0xd0, 0xae, 0x59, 0x6f, 0x77,
0x09, 0xed, 0x05, 0xcf, 0x73, 0x59, 0x21, 0x1f, 0x5c, 0x69, 0x21, 0x0b, 0x6c, 0xd5, 0x4d, 0xbd,
0x9c, 0x7e, 0x06, 0xd0, 0x99, 0xe1, 0x5f, 0x26, 0x09, 0x44, 0xcf, 0x8a, 0x53, 0xe3, 0x43, 0xba,
0x71, 0x3b, 0x35, 0xea, 0xa3, 0xba, 0x53, 0x4a, 0xaa, 0x99, 0xcc, 0x78, 0xdc, 0xb0, 0x67, 0xd8,
0x47, 0xfe, 0x67, 0x63, 0xc7, 0xec, 0xf5, 0x91, 0x6f, 0xc6, 0xf0, 0x7f, 0x2e, 0x34, 0x93, 0x76,
0x3c, 0x01, 0xac, 0xe2, 0x82, 0xa3, 0x83, 0xf7, 0xb8, 0xf1, 0xda, 0xc1, 0xcb, 0x74, 0xfb, 0x1d,
0x00, 0x00, 0xff, 0xff, 0x8e, 0x21, 0x38, 0xfd, 0x8f, 0x02, 0x00, 0x00,
}
......@@ -10,32 +10,30 @@ service Client {
rpc Discover(Hello) returns (Hello) {}
}
message Context {
bytes recipientKeyHash = 1; // SHA-512
bytes senderKeyHash = 2; // SHA-512
string signatureUuid = 3;
string contractUuid = 4;
string contractDocumentHash = 5;
}
// Promise message contains all the required information to verify
// the identity of the sender and receiver, and the actual promise
//
// * sequence is transmitted by platform and identical across clients
// * TODO implement an global signature for content
message Promise {
bytes recipientKeyHash = 1; // SHA-512
bytes senderKeyHash = 2; // SHA-512
uint32 index = 3; // The index of the sequence for this message
string contractDocumentHash = 4; // Hash of the contract to be signed
string signatureUuid = 5; // Avoid re-use of the promise in another ctx
string contractUuid = 6;
// TODO the crypto payload
Context context = 1;
uint32 index = 2;
bytes payload = 3;
}
// Signature message contains all the required information to verify
// the identity of the sender and receiver, and the actual signature
message Signature {
bytes recipientKeyHash = 1; // SHA-512
bytes senderKeyHash = 2; // SHA-512
string signature = 3; // Cryptographic signature
string signatureUuid = 4;
string contractUuid = 5;
Context context = 1;
bytes payload = 2;
}
// Hello message is used when discovering peers.
// Hello message is used when discovering peers.
// It contains the current version of the software.
message Hello {
string version = 1;
......
......@@ -139,7 +139,7 @@ func TestGetAllButOne(t *testing.T) {
assert.Equal(t, res[2], uint32(2))
}
func ExampleSequenceAnalysis() {
func ExampleFindNextIndex() {
s := []uint32{0, 1, 2, 0, 1, 2}
id := uint32(2)
......
......@@ -2,7 +2,6 @@ package sign
import (
"errors"
"fmt"
"time"
cAPI "dfss/dfssc/api"
......@@ -10,49 +9,75 @@ import (
pAPI "dfss/dfssp/api"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// CreatePromise creates a promise from 'from' to 'to', in the context of the SignatureManager
// provided the specified sequence indexes are valid
func (m *SignatureManager) CreatePromise(from, to uint32) (*cAPI.Promise, error) {
func (m *SignatureManager) createContext(from, to uint32) (*cAPI.Context, error) {
if int(from) >= len(m.keyHash) || int(to) >= len(m.keyHash) {
return nil, errors.New("Invalid id for promise creation")
}
if m.currentIndex < 0 {
return nil, errors.New("Invalid currentIndex for promise creation")
return nil, errors.New("Invalid id for context creation")
}
promise := &cAPI.Promise{
return &cAPI.Context{
RecipientKeyHash: m.keyHash[to],
SenderKeyHash: m.keyHash[from],
Index: uint32(m.currentIndex),
ContractDocumentHash: m.contract.File.Hash,
SignatureUuid: m.uuid,
ContractUuid: m.contract.UUID,
}
return promise, nil
}, nil
}
// SendPromise sends the specified promise to the specified peer
func (m *SignatureManager) SendPromise(promise *cAPI.Promise, to uint32) (*pAPI.ErrorCode, error) {
connection, err := m.GetClient(to)
// CreatePromise creates a promise from 'from' to 'to', in the context of the SignatureManager
// provided the specified sequence indexes are valid
func (m *SignatureManager) CreatePromise(from, to uint32) (*cAPI.Promise, error) {
context, err := m.createContext(from, to)
if err != nil {
return &pAPI.ErrorCode{}, err
return nil, err
}
if m.currentIndex < 0 {
return nil, errors.New("Invalid currentIndex for promise creation")
}
return &cAPI.Promise{
Index: uint32(m.currentIndex),
Context: context,
Payload: []byte{0x41},
}, nil
}
// SendEvidence factorizes the send code between promises and signatures.
// You can use it by setting either promise or signature to `nil`.
// The successfully sent evidence is then added to the archives.
func (m *SignatureManager) SendEvidence(promise *cAPI.Promise, signature *cAPI.Signature, to uint32) (err error) {
connection, mail := m.GetClient(to)
if connection == nil {
return
}
// Handle the timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
errCode, err := (*connection).TreatPromise(ctx, promise)
if err == grpc.ErrClientConnTimeout {
dAPI.DLog("Promise timeout for [" + fmt.Sprintf("%d", to) + "]")
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_TIMEOUT, Message: "promise timeout"}, err
} else if err != nil {
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_INTERR, Message: "internal server error"}, err
var result *pAPI.ErrorCode
if promise != nil {
result, err = (*connection).TreatPromise(ctx, promise)
} else if signature != nil {
result, err = (*connection).TreatSignature(ctx, signature)
} else {
err = errors.New("both promise and signature are nil, cannot send anything")
}
m.archives.sentPromises = append(m.archives.sentPromises, promise)
if err == nil && result != nil && result.Code == pAPI.ErrorCode_SUCCESS {
m.archives.mutex.Lock()
if promise != nil {
dAPI.DLog("sent promise to " + mail)
m.archives.sentPromises = append(m.archives.sentPromises, promise)
} else {
dAPI.DLog("sent signature to " + mail)
m.archives.sentSignatures = append(m.archives.sentSignatures, signature)
}
m.archives.mutex.Unlock()
} else {
dAPI.DLog("unable to send evidence to " + mail)
err = errors.New("received wrong error code")
}
return errCode, nil
return
}
......@@ -2,14 +2,14 @@ package sign
import (
"fmt"
"log"
"time"
cAPI "dfss/dfssc/api"
"dfss/dfssc/common"
dAPI "dfss/dfssd/api"
)
// Sign perform all the message exchanges for the contract to be signed
// Sign performs all the message exchanges for the contract to be signed
//
// * Initialize the SignatureManager from starter.go
// * Compute the reversed map [mail -> ID] of signers
......@@ -17,22 +17,22 @@ import (
// * Promises rounds
// * Signature round
func (m *SignatureManager) Sign() error {
myID, nextIndex, err := m.Initialize()
if err != nil {
return err
}
m.makeSignersHashToIDMap()
m.cServerIface.incomingPromises = make(chan interface{})
m.cServerIface.incomingSignatures = make(chan interface{})
m.cServerIface.incomingPromises = make(chan *cAPI.Promise)
m.cServerIface.incomingSignatures = make(chan *cAPI.Signature)
// Cooldown delay, let other clients wake-up their channels
time.Sleep(time.Second)
// Promess rounds
// Follow the sequence until there is no next occurence of me
for m.currentIndex >= 0 {
dAPI.DLog(fmt.Sprintf("{%d} ", myID) + "Starting round at index [" + fmt.Sprintf("%d", m.currentIndex) + "] with nextIndex=" + fmt.Sprintf("%d", nextIndex))
dAPI.DLog("starting round at index [" + fmt.Sprintf("%d", m.currentIndex) + "] with nextIndex=" + fmt.Sprintf("%d", nextIndex))
// Set of the promise we are waiting for
var pendingSet []uint32
......@@ -58,99 +58,69 @@ func (m *SignatureManager) Sign() error {
}
}
dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Enter signature round")
dAPI.DLog("entering signature round")
// Signature round
err = m.ExchangeAllSignatures()
if err != nil {
return err
}
dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Exit signature round")
dAPI.DLog("exiting signature round")
// 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
}
return nil
return m.platformConn.Close()
}
// 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
func (m *SignatureManager) GetClient(to uint32) (client *cAPI.ClientClient, mail string) {
mail = m.contract.Signers[to].Email
client = m.peers[mail]
return
}
// makeSignersHashToIDMap build an association to reverse a hash to the sequence ID
// makeSignersHashToIDMap builds an association to reverse a hash to the sequence ID
func (m *SignatureManager) makeSignersHashToIDMap() {
m.hashToID = make(map[string]uint32)
signers := m.contract.Signers
for id, signer := range signers {
m.hashToID[signer.Hash] = uint32(id)
}
}
// promiseRound describe a promise round: reception and sending
//
// promiseRound describes a promise round: reception and sending
// TODO better error management - this function should return `error` !
func (m *SignatureManager) promiseRound(pendingSet, sendSet []uint32, myID uint32) {
// Reception of the due promises
// TODO this ctx needs a timeout !
for len(pendingSet) > 0 {
promise := <-m.cServerIface.incomingPromises
senderID, exist := m.hashToID[fmt.Sprintf("%x", promise.SenderKeyHash)]
promise := (<-m.cServerIface.incomingPromises).(*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 {
_ = fmt.Errorf("Receive unexpected promise")
continue
}
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))
} else {
// Wrong sender keyHash
log.Println("{" + fmt.Sprintf("%d", myID) + "} Wrong sender keyhash !")
}
}
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 {
_ = fmt.Errorf("Failed to create promise from %d to %d", myID, id)
}
dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Send promise to " + fmt.Sprintf("%d", id))
_, err = m.SendPromise(promise, id)
if err != nil {
dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Promise have not been received !")
_ = fmt.Errorf("Failed to deliver promise from %d to %d", myID, id)
if err == nil {
_ = m.SendEvidence(promise, nil, id)
}
c <- promise
}(id, m)
}
// Verifying we sent all the due promises
for _ = range sendSet {
promise := <-c
if promise != nil {
m.archives.sentPromises = append(m.archives.sentPromises, promise)
} else {
// something appened during the goroutine
}
for range sendSet {
_ = <-c
}
}
......@@ -160,6 +130,5 @@ func (m *SignatureManager) closeAllPeerClient() {
_ = client.Close()
// Remove associated grpc client
delete(m.peers, k)
fmt.Println("- Close connection to " + k)
}
}
package sign
import (
"fmt"
"dfss"
cAPI "dfss/dfssc/api"
pAPI "dfss/dfssp/api"
......@@ -12,35 +10,30 @@ import (
)
type clientServer struct {
incomingPromises chan *cAPI.Promise
incomingSignatures chan *cAPI.Signature
incomingPromises chan interface{}
incomingSignatures chan interface{}
}
func getServerErrorCode(c chan interface{}, in interface{}) *pAPI.ErrorCode {
if c != nil {
c <- in
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_SUCCESS}
}
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_INTERR} // server not ready
}
// TreatPromise handler
//
// Handle incoming TreatPromise messages
func (s *clientServer) TreatPromise(ctx context.Context, in *cAPI.Promise) (*pAPI.ErrorCode, error) {
// Pass the message to Sign()
if s.incomingPromises != nil {
s.incomingPromises <- in
// Maybe we can add another channel here for better error management
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_SUCCESS}, nil
}
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_INVARG}, fmt.Errorf("Cannot pass incoming promise")
return getServerErrorCode(s.incomingPromises, in), nil
}
// TreatSignature handler
//
// Handle incoming TreatSignature messages
func (s *clientServer) TreatSignature(ctx context.Context, in *cAPI.Signature) (*pAPI.ErrorCode, error) {
if s.incomingSignatures != nil {
s.incomingSignatures <- in
// Maybe we can add another channel here for better error management
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_SUCCESS}, nil
}
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_INVARG}, fmt.Errorf("Cannot pass incoming signature")
return getServerErrorCode(s.incomingSignatures, in), nil
}
// Discover handler
......
......@@ -2,34 +2,24 @@ package sign
import (
"dfss/dfssc/common"
"errors"
"fmt"
"time"
cAPI "dfss/dfssc/api"
dAPI "dfss/dfssd/api"
pAPI "dfss/dfssp/api"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// ExchangeAllSignatures creates and sends signatures to all the signers of the contract
func (m *SignatureManager) ExchangeAllSignatures() error {
allReceived := make(chan error)
go m.ReceiveAllSigns(allReceived)
go m.ReceiveAllSignatures(allReceived)
myID, err := m.FindID()
if err != nil {
return err
}
// compute a set of all signers exept me
// compute a set of all signers except me
sendSet := common.GetAllButOne(m.sequence, myID)
errorChan := make(chan error)
for _, id := range sendSet {
go func(id uint32) {
signature, err2 := m.CreateSignature(myID, id)
......@@ -37,16 +27,12 @@ func (m *SignatureManager) ExchangeAllSignatures() error {
errorChan <- err2
return
}
dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Send sign to " + fmt.Sprintf("%d", id))
_, err2 = m.SendSignature(signature, id)
err2 = m.SendEvidence(nil, signature, id)
if err2 != nil {
errorChan <- err2
return
}
errorChan <- nil
return
}(id)
}
......@@ -57,57 +43,25 @@ func (m *SignatureManager) ExchangeAllSignatures() error {
}
}
err = <-allReceived
if err != nil {
return err
}
return nil
return <-allReceived
}
// CreateSignature creates a signature from a sequence ID to another
// provided the specified sequence indexes are valid
// TODO Implement a true cryptographic signature
func (m *SignatureManager) CreateSignature(from, to uint32) (*cAPI.Signature, error) {
if int(from) >= len(m.keyHash) || int(to) >= len(m.keyHash) {
return &cAPI.Signature{}, errors.New("Invalid id for signature creation")
}
signature := &cAPI.Signature{
RecipientKeyHash: m.keyHash[to],
SenderKeyHash: m.keyHash[from],
Signature: "Signature",
SignatureUuid: m.uuid,
ContractUuid: m.contract.UUID,
}
return signature, nil
}
// SendSignature sends the specified signature to the specified peer
func (m *SignatureManager) SendSignature(signature *cAPI.Signature, to uint32) (*pAPI.ErrorCode, error) {
connection, err := m.GetClient(to)
context, err := m.createContext(from, to)
if err != nil {
return &pAPI.ErrorCode{}, err
return nil, err
}
// Handle the timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
errCode, err := (*connection).TreatSignature(ctx, signature)
if err == grpc.ErrClientConnTimeout {
dAPI.DLog("Signature timeout for [" + fmt.Sprintf("%d", to) + "]")
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_TIMEOUT, Message: "signature timeout"}, err
} else if err != nil {
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_INTERR, Message: "internal server error"}, err
}
m.archives.sentSignatures = append(m.archives.sentSignatures, signature)
return errCode, nil
return &cAPI.Signature{
Context: context,
Payload: []byte{0x42},
}, nil
}
// ReceiveAllSigns receive all the signatures
func (m *SignatureManager) ReceiveAllSigns(out chan error) {
// ReceiveAllSignatures receive all the signatures
func (m *SignatureManager) ReceiveAllSignatures(out chan error) {
myID, err := m.FindID()
if err != nil {
out <- err
......@@ -119,18 +73,11 @@ func (m *SignatureManager) ReceiveAllSigns(out chan error) {
// TODO this ctx needs a timeout !
for len(pendingSet) > 0 {
signature := <-m.cServerIface.incomingSignatures
senderID, exist := m.hashToID[fmt.Sprintf("%x", signature.SenderKeyHash)]
dAPI.DLog("{" + fmt.Sprintf("%d", myID) + "} Receive sign from " + fmt.Sprintf("%d", senderID))
signature := (<-m.cServerIface.incomingSignatures).(*cAPI.Signature)
senderID, exist := m.hashToID[fmt.Sprintf("%x", signature.Context.SenderKeyHash)]
if exist {
var err error
pendingSet, err = common.Remove(pendingSet, senderID)
if err != nil {
// Receive unexpected signature, ignore ?
}
pendingSet, _ = common.Remove(pendingSet, senderID)
m.archives.receivedSignatures = append(m.archives.receivedSignatures, signature)
} else {
// Wrong sender keyHash
}
}
......
......@@ -5,6 +5,7 @@ import (
"fmt"
"log"
"strconv"
"sync"
"time"
"dfss"
......@@ -45,6 +46,7 @@ type Archives struct {
receivedPromises []*cAPI.Promise
sentSignatures []*cAPI.Signature
receivedSignatures []*cAPI.Signature
mutex sync.Mutex
}
// NewSignatureManager populates a SignatureManager and connects to the platform.
......
......@@ -132,15 +132,16 @@ var _Demonstrator_serviceDesc = grpc.ServiceDesc{
}
var fileDescriptor0 = []byte{
// 159 bytes of a gzipped FileDescriptorProto
// 167 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x4c, 0x49, 0x2b, 0x2e,
0xd6, 0x07, 0x11, 0x29, 0xfa, 0x89, 0x05, 0x99, 0xfa, 0x29, 0xa9, 0xb9, 0xf9, 0x79, 0xc5, 0x25,
0x45, 0x89, 0x25, 0xf9, 0x45, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xcc, 0x40, 0x71, 0x25,
0x4b, 0x2e, 0x66, 0x9f, 0xfc, 0x74, 0x21, 0x41, 0x2e, 0xce, 0x92, 0xcc, 0xdc, 0xd4, 0xe2, 0x92,
0xc4, 0xdc, 0x02, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x66, 0x21, 0x21, 0x2e, 0xae, 0xcc, 0x94, 0xd4,
0xbc, 0x92, 0xcc, 0xb4, 0xcc, 0xd4, 0x22, 0x09, 0x26, 0xa0, 0x18, 0xa7, 0x10, 0x37, 0x17, 0x73,
0x4e, 0x7e, 0xba, 0x04, 0x33, 0x88, 0xa3, 0xc4, 0xca, 0xc5, 0xec, 0x98, 0x9c, 0x6d, 0xa4, 0xcf,
0xc5, 0xe3, 0x82, 0x64, 0xb8, 0x90, 0x3c, 0x17, 0x7b, 0x70, 0x6a, 0x5e, 0x0a, 0xc8, 0x54, 0x0e,