veyron/runtimes/google/ipc: fix a bug in caching blessings.

  o The bug makes a client to send its blessing for every new flow
    without using a cached one causing the server validating the same
    blessing repeatedly.
  o IPC benchmark 'Benchmark___10B' shows the latency of a single Echo call
    is reduced from 8.03ms to 5.66ms.
  o Also fixed a bug in using blessings instance (pointer) as cache key,
    which makes the cache under utilized.

Change-Id: Ibda83271236638a0c4aad550480fd78a11347191
diff --git a/runtimes/google/ipc/blessings_cache.go b/runtimes/google/ipc/blessings_cache.go
index effa8e8..119c3db 100644
--- a/runtimes/google/ipc/blessings_cache.go
+++ b/runtimes/google/ipc/blessings_cache.go
@@ -1,6 +1,7 @@
 package ipc
 
 import (
+	"crypto/sha256"
 	"fmt"
 	"reflect"
 	"sync"
@@ -12,7 +13,7 @@
 
 // clientEncodeBlessings gets or inserts the blessings into the cache.
 func clientEncodeBlessings(cache stream.VCDataCache, blessings security.Blessings) ipc.BlessingsRequest {
-	blessingsCacheAny := cache.GetOrInsert(clientBlessingsKey{}, newClientBlessingsCache)
+	blessingsCacheAny := cache.GetOrInsert(clientBlessingsCacheKey{}, newClientBlessingsCache)
 	blessingsCache := blessingsCacheAny.(*clientBlessingsCache)
 	return blessingsCache.getOrInsert(blessings)
 }
@@ -20,7 +21,7 @@
 // clientAckBlessings verifies that the server has updated its cache to include blessings.
 // This means that subsequent rpcs from the client with blessings can send only a cache key.
 func clientAckBlessings(cache stream.VCDataCache, blessings security.Blessings) {
-	blessingsCacheAny := cache.GetOrInsert(clientBlessingsKey{}, newClientBlessingsCache)
+	blessingsCacheAny := cache.GetOrInsert(clientBlessingsCacheKey{}, newClientBlessingsCache)
 	blessingsCache := blessingsCacheAny.(*clientBlessingsCache)
 	blessingsCache.acknowledge(blessings)
 }
@@ -28,77 +29,94 @@
 // serverDecodeBlessings insert the key and blessings into the cache or get the blessings if only
 // key is provided in req.
 func serverDecodeBlessings(cache stream.VCDataCache, req ipc.BlessingsRequest, stats *ipcStats) (security.Blessings, error) {
-	blessingsCacheAny := cache.GetOrInsert(serverBlessingsKey{}, newServerBlessingsCache)
+	blessingsCacheAny := cache.GetOrInsert(serverBlessingsCacheKey{}, newServerBlessingsCache)
 	blessingsCache := blessingsCacheAny.(*serverBlessingsCache)
 	return blessingsCache.getOrInsert(req, stats)
 }
 
 // IMPLEMENTATION DETAILS BELOW
 
-// clientBlessingsCache is a thread-safe map from blessings to cache key.
+// clientBlessingsCache is a thread-safe map from blessings to cache id.
 type clientBlessingsCache struct {
 	sync.RWMutex
-	m   map[security.Blessings]clientCacheValue
-	key uint64
+	m     map[[sha256.Size]byte]clientCacheValue
+	curId uint64
 }
 
 type clientCacheValue struct {
-	key uint64
-	// ack is set to true once the server has confirmed receipt of the cache key.
-	// Clients that insert into the cache when ack is false must send both the key
+	id uint64
+	// ack is set to true once the server has confirmed receipt of the cache id.
+	// Clients that insert into the cache when ack is false must send both the id
 	// and the blessings.
 	ack bool
 }
 
-// clientBlessingsKey is the key used to retrieve the clientBlessingsCache from the VCDataCache.
-type clientBlessingsKey struct{}
+// clientBlessingsCacheKey is the key used to retrieve the clientBlessingsCache from the VCDataCache.
+type clientBlessingsCacheKey struct{}
 
 func newClientBlessingsCache() interface{} {
-	return &clientBlessingsCache{m: make(map[security.Blessings]clientCacheValue)}
+	return &clientBlessingsCache{m: make(map[[sha256.Size]byte]clientCacheValue)}
+}
+
+func getBlessingsHashKey(blessings security.Blessings) (key [sha256.Size]byte) {
+	h := sha256.New()
+	for _, chain := range security.MarshalBlessings(blessings).CertificateChains {
+		if len(chain) == 0 {
+			continue
+		}
+		cert := chain[len(chain)-1]
+		s := sha256.Sum256(cert.Signature.R)
+		h.Write(s[:])
+		s = sha256.Sum256(cert.Signature.S)
+		h.Write(s[:])
+	}
+	copy(key[:], h.Sum(nil))
+	return
 }
 
 func (c *clientBlessingsCache) getOrInsert(blessings security.Blessings) ipc.BlessingsRequest {
+	key := getBlessingsHashKey(blessings)
 	c.RLock()
-	val, exists := c.m[blessings]
+	val, exists := c.m[key]
 	c.RUnlock()
 	if exists {
 		return c.makeBlessingsRequest(val, blessings)
 	}
-	// if the val doesn't exist we must create a new key, update the cache, and send the key and blessings.
+	// If the val doesn't exist we must create a new id, update the cache, and send the id and blessings.
 	c.Lock()
-	defer c.Unlock()
-	// we must check that the val wasn't inserted in the time we changed locks.
-	val, exists = c.m[blessings]
-	if exists {
-		return c.makeBlessingsRequest(val, blessings)
+	// We must check that the val wasn't inserted in the time we changed locks.
+	val, exists = c.m[key]
+	if !exists {
+		val = clientCacheValue{id: c.nextIdLocked()}
+		c.m[key] = val
 	}
-	newVal := clientCacheValue{key: c.nextKeyLocked()}
-	c.m[blessings] = newVal
-	return c.makeBlessingsRequest(newVal, blessings)
+	c.Unlock()
+	return c.makeBlessingsRequest(val, blessings)
 }
 
 func (c *clientBlessingsCache) acknowledge(blessings security.Blessings) {
+	key := getBlessingsHashKey(blessings)
 	c.Lock()
-	val := c.m[blessings]
+	val := c.m[key]
 	val.ack = true
-	c.m[blessings] = val
+	c.m[key] = val
 	c.Unlock()
 }
 
 func (c *clientBlessingsCache) makeBlessingsRequest(val clientCacheValue, blessings security.Blessings) ipc.BlessingsRequest {
 	if val.ack {
 		// when the value is acknowledged, only send the key, since the server has confirmed that it knows the key.
-		return ipc.BlessingsRequest{Key: val.key}
+		return ipc.BlessingsRequest{Key: val.id}
 	}
 	// otherwise we still need to send both key and blessings, but we must ensure that we send the same key.
 	wireBlessings := security.MarshalBlessings(blessings)
-	return ipc.BlessingsRequest{val.key, &wireBlessings}
+	return ipc.BlessingsRequest{val.id, &wireBlessings}
 }
 
-// nextKeyLocked creates a new key for inserting blessings. It must be called after acquiring a writer lock.
-func (c *clientBlessingsCache) nextKeyLocked() uint64 {
-	c.key++
-	return c.key
+// nextIdLocked creates a new id for inserting blessings. It must be called after acquiring a writer lock.
+func (c *clientBlessingsCache) nextIdLocked() uint64 {
+	c.curId++
+	return c.curId
 }
 
 // serverBlessingsCache is a thread-safe map from cache key to blessings.
@@ -107,8 +125,8 @@
 	m map[uint64]security.Blessings
 }
 
-// serverBlessingsKey is the key used to retrieve the serverBlessingsCache from the VCDataCache.
-type serverBlessingsKey struct{}
+// serverBlessingsCacheKey is the key used to retrieve the serverBlessingsCache from the VCDataCache.
+type serverBlessingsCacheKey struct{}
 
 func newServerBlessingsCache() interface{} {
 	return &serverBlessingsCache{m: make(map[uint64]security.Blessings)}
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 6ef039b..a472e68 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -736,8 +736,8 @@
 	// Encode the Blessings information for the client to authorize the flow.
 	var blessingsRequest ipc.BlessingsRequest
 	if fc.flow.LocalPrincipal() != nil {
-		localBlessings := fc.flow.LocalPrincipal().BlessingStore().ForPeer(fc.server...)
-		blessingsRequest = clientEncodeBlessings(fc.flow.VCDataCache(), localBlessings)
+		fc.blessings = fc.flow.LocalPrincipal().BlessingStore().ForPeer(fc.server...)
+		blessingsRequest = clientEncodeBlessings(fc.flow.VCDataCache(), fc.blessings)
 	}
 	// TODO(suharshs, ataly): Make security.Discharge a vdl type.
 	anyDischarges := make([]vdlutil.Any, len(fc.discharges))
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 432242e..e9b7066 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -1118,7 +1118,9 @@
 		fs.server.streamMgr.ShutdownEndpoint(fs.RemoteEndpoint())
 		return old_verror.BadProtocolf("ipc: blessings cache failed: %v", err)
 	}
-	fs.ackBlessings = true
+	if fs.clientBlessings != nil {
+		fs.ackBlessings = true
+	}
 
 	// TODO(suharshs, ataly): Make security.Discharge a vdl type.
 	for i, d := range req.Discharges {