ref: Persist discharges.

The discharge cache is moved into the blessingStore so that discharges
may be used across processes.

On my machine, the first call of
'namespace glob identity' with a blessing that has a revocation caveat
takes .7s, but subsequent calls take .25 seconds.

MultiPart: 2/2

Change-Id: Ifdc23e618120baef1638b2ebda1f900b772ce727
diff --git a/services/agent/agentlib/client.go b/services/agent/agentlib/client.go
index 7dc2c3c..2efad70 100644
--- a/services/agent/agentlib/client.go
+++ b/services/agent/agentlib/client.go
@@ -252,6 +252,28 @@
 	return
 }
 
+func (b *blessingStore) CacheDischarge(d security.Discharge, c security.Caveat, i security.DischargeImpetus) {
+	err := b.caller.call("BlessingStoreCacheDischarge", results(), d, c, i)
+	if err != nil {
+		vlog.Errorf("error calling BlessingStoreCacheDischarge: %v", err)
+	}
+}
+
+func (b *blessingStore) ClearDischarges(discharges ...security.Discharge) {
+	err := b.caller.call("BlessingStoreClearDischarges", results(), discharges)
+	if err != nil {
+		vlog.Errorf("error calling BlessingStoreClearDischarges: %v", err)
+	}
+}
+
+func (b *blessingStore) Discharge(caveat security.Caveat, impetus security.DischargeImpetus) (out security.Discharge) {
+	err := b.caller.call("BlessingStoreDischarge", results(&out), caveat, impetus)
+	if err != nil {
+		vlog.Errorf("error calling BlessingStoreDischarge: %v", err)
+	}
+	return
+}
+
 type blessingRoots struct {
 	caller caller
 }
diff --git a/services/agent/internal/cache/cache.go b/services/agent/internal/cache/cache.go
index cc6b904..70bca36 100644
--- a/services/agent/internal/cache/cache.go
+++ b/services/agent/internal/cache/cache.go
@@ -312,6 +312,24 @@
 	return fmt.Sprintf("cached[%s]", s.impl)
 }
 
+func (s *cachedStore) CacheDischarge(d security.Discharge, c security.Caveat, i security.DischargeImpetus) {
+	s.mu.Lock()
+	s.impl.CacheDischarge(d, c, i)
+	s.mu.Unlock()
+}
+
+func (s *cachedStore) ClearDischarges(discharges ...security.Discharge) {
+	s.mu.Lock()
+	s.impl.ClearDischarges(discharges...)
+	s.mu.Unlock()
+}
+
+func (s *cachedStore) Discharge(caveat security.Caveat, impetus security.DischargeImpetus) security.Discharge {
+	defer s.mu.Unlock()
+	s.mu.Lock()
+	return s.impl.Discharge(caveat, impetus)
+}
+
 // Must be called while holding mu.
 func (s *cachedStore) flush() {
 	s.hasDef = false
diff --git a/services/agent/internal/server/server.go b/services/agent/internal/server/server.go
index 893d4e7..eab49a2 100644
--- a/services/agent/internal/server/server.go
+++ b/services/agent/internal/server/server.go
@@ -403,6 +403,26 @@
 	return a.principal.BlessingStore().Default(), nil
 }
 
+func (a agentd) BlessingStoreCacheDischarge(_ *context.T, _ rpc.ServerCall, discharge security.Discharge, caveat security.Caveat, impetus security.DischargeImpetus) error {
+	a.w.lock()
+	a.principal.BlessingStore().CacheDischarge(discharge, caveat, impetus)
+	a.w.unlock(a.id)
+	return nil
+}
+
+func (a agentd) BlessingStoreClearDischarges(_ *context.T, _ rpc.ServerCall, discharges []security.Discharge) error {
+	a.w.lock()
+	a.principal.BlessingStore().ClearDischarges(discharges...)
+	a.w.unlock(a.id)
+	return nil
+}
+
+func (a agentd) BlessingStoreDischarge(_ *context.T, _ rpc.ServerCall, caveat security.Caveat, impetus security.DischargeImpetus) (security.Discharge, error) {
+	a.w.lock()
+	defer a.w.unlock(a.id)
+	return a.principal.BlessingStore().Discharge(caveat, impetus), nil
+}
+
 func (a agentd) BlessingRootsAdd(_ *context.T, _ rpc.ServerCall, root []byte, pattern security.BlessingPattern) error {
 	pkey, err := security.UnmarshalPublicKey(root)
 	if err != nil {
diff --git a/services/agent/internal/test_principal/main.go b/services/agent/internal/test_principal/main.go
index 28cc564..7887d67 100644
--- a/services/agent/internal/test_principal/main.go
+++ b/services/agent/internal/test_principal/main.go
@@ -94,7 +94,8 @@
 	if err != nil {
 		errorf("security.NewPublicKeyCaveat: %v", err)
 	}
-	if _, err := p.MintDischarge(tpcav, cav); err != nil {
+	dis, err := p.MintDischarge(tpcav, cav)
+	if err != nil {
 		errorf("MintDischarge: %v", err)
 	}
 	// BlessingRoots
@@ -134,6 +135,14 @@
 	if forpeer := p.BlessingStore().ForPeer("superman/friend"); !reflect.DeepEqual(forpeer, b) {
 		errorf("BlessingStore().ForPeer returned %v and not %v", forpeer, b)
 	}
+	p.BlessingStore().CacheDischarge(dis, tpcav, security.DischargeImpetus{})
+	if got := p.BlessingStore().Discharge(tpcav, security.DischargeImpetus{}); !dis.Equivalent(got) {
+		errorf("BlessingStore().Discharges returned %#v want %#v", got, dis)
+	}
+	p.BlessingStore().ClearDischarges(dis)
+	if got := p.BlessingStore().Discharge(tpcav, security.DischargeImpetus{}); got.ID() != "" {
+		errorf("BlessingStore().Discharges returned %#v want empty", got)
+	}
 
 	if len(errors) > 0 {
 		// Print out all errors and exit with failure.
diff --git a/services/agent/wire.vdl b/services/agent/wire.vdl
index 994aaf5..1d92fcc 100644
--- a/services/agent/wire.vdl
+++ b/services/agent/wire.vdl
@@ -52,6 +52,9 @@
 	BlessingStoreDefault() (security.WireBlessings | error)
 	BlessingStorePeerBlessings() (map[security.BlessingPattern]security.WireBlessings | error)
 	BlessingStoreDebugString() (string | error)
+	BlessingStoreCacheDischarge(discharge security.WireDischarge, caveat security.Caveat, impetus security.DischargeImpetus) error
+	BlessingStoreClearDischarges(discharges []security.WireDischarge) error
+	BlessingStoreDischarge(caveat security.Caveat, impetus security.DischargeImpetus) (wd security.WireDischarge | error)
 
 	BlessingRootsAdd(root []byte, pattern security.BlessingPattern) error
 	BlessingRootsRecognized(root []byte, blessing string) error
diff --git a/services/agent/wire.vdl.go b/services/agent/wire.vdl.go
index 1a0e6a2..da18067 100644
--- a/services/agent/wire.vdl.go
+++ b/services/agent/wire.vdl.go
@@ -63,6 +63,9 @@
 	BlessingStoreDefault(*context.T, ...rpc.CallOpt) (security.Blessings, error)
 	BlessingStorePeerBlessings(*context.T, ...rpc.CallOpt) (map[security.BlessingPattern]security.Blessings, error)
 	BlessingStoreDebugString(*context.T, ...rpc.CallOpt) (string, error)
+	BlessingStoreCacheDischarge(ctx *context.T, discharge security.Discharge, caveat security.Caveat, impetus security.DischargeImpetus, opts ...rpc.CallOpt) error
+	BlessingStoreClearDischarges(ctx *context.T, discharges []security.Discharge, opts ...rpc.CallOpt) error
+	BlessingStoreDischarge(ctx *context.T, caveat security.Caveat, impetus security.DischargeImpetus, opts ...rpc.CallOpt) (wd security.Discharge, err error)
 	BlessingRootsAdd(ctx *context.T, root []byte, pattern security.BlessingPattern, opts ...rpc.CallOpt) error
 	BlessingRootsRecognized(ctx *context.T, root []byte, blessing string, opts ...rpc.CallOpt) error
 	BlessingRootsDump(*context.T, ...rpc.CallOpt) (map[security.BlessingPattern][][]byte, error)
@@ -159,6 +162,21 @@
 	return
 }
 
+func (c implAgentClientStub) BlessingStoreCacheDischarge(ctx *context.T, i0 security.Discharge, i1 security.Caveat, i2 security.DischargeImpetus, opts ...rpc.CallOpt) (err error) {
+	err = v23.GetClient(ctx).Call(ctx, c.name, "BlessingStoreCacheDischarge", []interface{}{i0, i1, i2}, nil, opts...)
+	return
+}
+
+func (c implAgentClientStub) BlessingStoreClearDischarges(ctx *context.T, i0 []security.Discharge, opts ...rpc.CallOpt) (err error) {
+	err = v23.GetClient(ctx).Call(ctx, c.name, "BlessingStoreClearDischarges", []interface{}{i0}, nil, opts...)
+	return
+}
+
+func (c implAgentClientStub) BlessingStoreDischarge(ctx *context.T, i0 security.Caveat, i1 security.DischargeImpetus, opts ...rpc.CallOpt) (o0 security.Discharge, err error) {
+	err = v23.GetClient(ctx).Call(ctx, c.name, "BlessingStoreDischarge", []interface{}{i0, i1}, []interface{}{&o0}, opts...)
+	return
+}
+
 func (c implAgentClientStub) BlessingRootsAdd(ctx *context.T, i0 []byte, i1 security.BlessingPattern, opts ...rpc.CallOpt) (err error) {
 	err = v23.GetClient(ctx).Call(ctx, c.name, "BlessingRootsAdd", []interface{}{i0, i1}, nil, opts...)
 	return
@@ -273,6 +291,9 @@
 	BlessingStoreDefault(*context.T, rpc.ServerCall) (security.Blessings, error)
 	BlessingStorePeerBlessings(*context.T, rpc.ServerCall) (map[security.BlessingPattern]security.Blessings, error)
 	BlessingStoreDebugString(*context.T, rpc.ServerCall) (string, error)
+	BlessingStoreCacheDischarge(ctx *context.T, call rpc.ServerCall, discharge security.Discharge, caveat security.Caveat, impetus security.DischargeImpetus) error
+	BlessingStoreClearDischarges(ctx *context.T, call rpc.ServerCall, discharges []security.Discharge) error
+	BlessingStoreDischarge(ctx *context.T, call rpc.ServerCall, caveat security.Caveat, impetus security.DischargeImpetus) (wd security.Discharge, err error)
 	BlessingRootsAdd(ctx *context.T, call rpc.ServerCall, root []byte, pattern security.BlessingPattern) error
 	BlessingRootsRecognized(ctx *context.T, call rpc.ServerCall, root []byte, blessing string) error
 	BlessingRootsDump(*context.T, rpc.ServerCall) (map[security.BlessingPattern][][]byte, error)
@@ -303,6 +324,9 @@
 	BlessingStoreDefault(*context.T, rpc.ServerCall) (security.Blessings, error)
 	BlessingStorePeerBlessings(*context.T, rpc.ServerCall) (map[security.BlessingPattern]security.Blessings, error)
 	BlessingStoreDebugString(*context.T, rpc.ServerCall) (string, error)
+	BlessingStoreCacheDischarge(ctx *context.T, call rpc.ServerCall, discharge security.Discharge, caveat security.Caveat, impetus security.DischargeImpetus) error
+	BlessingStoreClearDischarges(ctx *context.T, call rpc.ServerCall, discharges []security.Discharge) error
+	BlessingStoreDischarge(ctx *context.T, call rpc.ServerCall, caveat security.Caveat, impetus security.DischargeImpetus) (wd security.Discharge, err error)
 	BlessingRootsAdd(ctx *context.T, call rpc.ServerCall, root []byte, pattern security.BlessingPattern) error
 	BlessingRootsRecognized(ctx *context.T, call rpc.ServerCall, root []byte, blessing string) error
 	BlessingRootsDump(*context.T, rpc.ServerCall) (map[security.BlessingPattern][][]byte, error)
@@ -399,6 +423,18 @@
 	return s.impl.BlessingStoreDebugString(ctx, call)
 }
 
+func (s implAgentServerStub) BlessingStoreCacheDischarge(ctx *context.T, call rpc.ServerCall, i0 security.Discharge, i1 security.Caveat, i2 security.DischargeImpetus) error {
+	return s.impl.BlessingStoreCacheDischarge(ctx, call, i0, i1, i2)
+}
+
+func (s implAgentServerStub) BlessingStoreClearDischarges(ctx *context.T, call rpc.ServerCall, i0 []security.Discharge) error {
+	return s.impl.BlessingStoreClearDischarges(ctx, call, i0)
+}
+
+func (s implAgentServerStub) BlessingStoreDischarge(ctx *context.T, call rpc.ServerCall, i0 security.Caveat, i1 security.DischargeImpetus) (security.Discharge, error) {
+	return s.impl.BlessingStoreDischarge(ctx, call, i0, i1)
+}
+
 func (s implAgentServerStub) BlessingRootsAdd(ctx *context.T, call rpc.ServerCall, i0 []byte, i1 security.BlessingPattern) error {
 	return s.impl.BlessingRootsAdd(ctx, call, i0, i1)
 }
@@ -552,6 +588,30 @@
 			},
 		},
 		{
+			Name: "BlessingStoreCacheDischarge",
+			InArgs: []rpc.ArgDesc{
+				{"discharge", ``}, // security.Discharge
+				{"caveat", ``},    // security.Caveat
+				{"impetus", ``},   // security.DischargeImpetus
+			},
+		},
+		{
+			Name: "BlessingStoreClearDischarges",
+			InArgs: []rpc.ArgDesc{
+				{"discharges", ``}, // []security.Discharge
+			},
+		},
+		{
+			Name: "BlessingStoreDischarge",
+			InArgs: []rpc.ArgDesc{
+				{"caveat", ``},  // security.Caveat
+				{"impetus", ``}, // security.DischargeImpetus
+			},
+			OutArgs: []rpc.ArgDesc{
+				{"wd", ``}, // security.Discharge
+			},
+		},
+		{
 			Name: "BlessingRootsAdd",
 			InArgs: []rpc.ArgDesc{
 				{"root", ``},    // []byte