Merge branch 'decode2' into decode3

Change-Id: I1551d440da0f2c9198d8aec72c089f8c05188a67
diff --git a/.gitignore b/.gitignore
index cd0b069..5854afc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@
 go/bin
 xunit.xml
 tmp
+.idea
 
 # Vanadium
 /.v23
diff --git a/extension/manifest.json b/extension/manifest.json
index ab38291..f2e9a2e 100644
--- a/extension/manifest.json
+++ b/extension/manifest.json
@@ -1,6 +1,6 @@
 {
   "name": "Vanadium Extension",
-  "version": "0.1.8",
+  "version": "0.1.9",
   "description": "Access and create Vanadium services from JavaScript.",
   "manifest_version": 2,
   "icons": {
diff --git a/src/gen-vdl/v.io/v23/vom/testdata/index.js b/src/gen-vdl/v.io/v23/vom/testdata/index.js
index 6757508..c1e5296 100644
--- a/src/gen-vdl/v.io/v23/vom/testdata/index.js
+++ b/src/gen-vdl/v.io/v23/vom/testdata/index.js
@@ -22,6 +22,8 @@
 var _type12 = new vdl.Type();
 var _type13 = new vdl.Type();
 var _type14 = new vdl.Type();
+var _type15 = new vdl.Type();
+var _type16 = new vdl.Type();
 var _type2 = new vdl.Type();
 var _type3 = new vdl.Type();
 var _type4 = new vdl.Type();
@@ -85,6 +87,8 @@
 var _typeSetOnlyMap = new vdl.Type();
 var _typeSetStructMap = new vdl.Type();
 var _typeSometimesSetMap = new vdl.Type();
+var _typeStructAny = new vdl.Type();
+var _typeStructMap = new vdl.Type();
 var _typeStructOnlyMap = new vdl.Type();
 var _typeTestCase = new vdl.Type();
 var _typeVomdataStruct = new vdl.Type();
@@ -94,22 +98,29 @@
 _type1.kind = vdl.kind.LIST;
 _type1.name = "";
 _type1.elem = _typeTestCase;
-_type10.kind = vdl.kind.LIST;
+_type10.kind = vdl.kind.MAP;
 _type10.name = "";
-_type10.elem = vdl.types.INT32;
+_type10.elem = _type11;
+_type10.key = vdl.types.STRING;
 _type11.kind = vdl.kind.LIST;
 _type11.name = "";
-_type11.elem = vdl.types.STRING;
-_type12.kind = vdl.kind.MAP;
+_type11.elem = vdl.types.TYPEOBJECT;
+_type12.kind = vdl.kind.LIST;
 _type12.name = "";
-_type12.elem = _type13;
-_type12.key = vdl.types.STRING;
+_type12.elem = vdl.types.INT32;
 _type13.kind = vdl.kind.LIST;
 _type13.name = "";
-_type13.elem = _typeConvertGroup;
-_type14.kind = vdl.kind.LIST;
+_type13.elem = vdl.types.STRING;
+_type14.kind = vdl.kind.MAP;
 _type14.name = "";
-_type14.elem = vdl.types.ANY;
+_type14.elem = _type15;
+_type14.key = vdl.types.STRING;
+_type15.kind = vdl.kind.LIST;
+_type15.name = "";
+_type15.elem = _typeConvertGroup;
+_type16.kind = vdl.kind.LIST;
+_type16.name = "";
+_type16.elem = vdl.types.ANY;
 _type2.kind = vdl.kind.LIST;
 _type2.name = "";
 _type2.elem = vdl.types.BYTE;
@@ -131,11 +142,11 @@
 _type7.elem = _typeRecStruct;
 _type8.kind = vdl.kind.MAP;
 _type8.name = "";
-_type8.elem = _type9;
-_type8.key = vdl.types.STRING;
-_type9.kind = vdl.kind.LIST;
+_type8.elem = vdl.types.INT64;
+_type8.key = vdl.types.INT64;
+_type9.kind = vdl.kind.OPTIONAL;
 _type9.name = "";
-_type9.elem = vdl.types.TYPEOBJECT;
+_type9.elem = _typeStructAny;
 _typeAbcStruct.kind = vdl.kind.STRUCT;
 _typeAbcStruct.name = "v.io/v23/vom/testdata.AbcStruct";
 _typeAbcStruct.fields = [{name: "A", type: vdl.types.BOOL}, {name: "B", type: vdl.types.STRING}, {name: "C", type: vdl.types.INT64}];
@@ -161,7 +172,7 @@
 _typeBrieEnum.labels = ["Glee", "Brie", "Three"];
 _typeConvertGroup.kind = vdl.kind.STRUCT;
 _typeConvertGroup.name = "v.io/v23/vom/testdata.ConvertGroup";
-_typeConvertGroup.fields = [{name: "Name", type: vdl.types.STRING}, {name: "PrimaryType", type: vdl.types.TYPEOBJECT}, {name: "Values", type: _type14}];
+_typeConvertGroup.fields = [{name: "Name", type: vdl.types.STRING}, {name: "PrimaryType", type: vdl.types.TYPEOBJECT}, {name: "Values", type: _type16}];
 _typeFoodEnum.kind = vdl.kind.ENUM;
 _typeFoodEnum.name = "v.io/v23/vom/testdata.FoodEnum";
 _typeFoodEnum.labels = ["Bean", "Brie", "Cherry"];
@@ -300,6 +311,12 @@
 _typeSometimesSetMap.name = "v.io/v23/vom/testdata.SometimesSetMap";
 _typeSometimesSetMap.elem = vdl.types.ANY;
 _typeSometimesSetMap.key = vdl.types.FLOAT64;
+_typeStructAny.kind = vdl.kind.STRUCT;
+_typeStructAny.name = "v.io/v23/vom/testdata.StructAny";
+_typeStructAny.fields = [{name: "Any", type: vdl.types.ANY}];
+_typeStructMap.kind = vdl.kind.STRUCT;
+_typeStructMap.name = "v.io/v23/vom/testdata.StructMap";
+_typeStructMap.fields = [{name: "Map", type: _type8}];
 _typeStructOnlyMap.kind = vdl.kind.MAP;
 _typeStructOnlyMap.name = "v.io/v23/vom/testdata.StructOnlyMap";
 _typeStructOnlyMap.elem = vdl.types.UINT64;
@@ -309,7 +326,7 @@
 _typeTestCase.fields = [{name: "Name", type: vdl.types.STRING}, {name: "Value", type: vdl.types.ANY}, {name: "TypeString", type: vdl.types.STRING}, {name: "Hex", type: vdl.types.STRING}, {name: "HexVersion", type: vdl.types.STRING}, {name: "HexType", type: vdl.types.STRING}, {name: "HexValue", type: vdl.types.STRING}];
 _typeVomdataStruct.kind = vdl.kind.STRUCT;
 _typeVomdataStruct.name = "v.io/v23/vom/testdata.VomdataStruct";
-_typeVomdataStruct.fields = [{name: "EncodeDecodeData", type: _type14}, {name: "CompatData", type: _type8}, {name: "ConvertData", type: _type12}];
+_typeVomdataStruct.fields = [{name: "EncodeDecodeData", type: _type16}, {name: "CompatData", type: _type10}, {name: "ConvertData", type: _type14}];
 _typeXyzStruct.kind = vdl.kind.STRUCT;
 _typeXyzStruct.name = "v.io/v23/vom/testdata.XyzStruct";
 _typeXyzStruct.fields = [{name: "X", type: vdl.types.BOOL}, {name: "Y", type: _typeMBool}, {name: "Z", type: vdl.types.STRING}];
@@ -325,6 +342,8 @@
 _type12.freeze();
 _type13.freeze();
 _type14.freeze();
+_type15.freeze();
+_type16.freeze();
 _type2.freeze();
 _type3.freeze();
 _type4.freeze();
@@ -388,6 +407,8 @@
 _typeSetOnlyMap.freeze();
 _typeSetStructMap.freeze();
 _typeSometimesSetMap.freeze();
+_typeStructAny.freeze();
+_typeStructMap.freeze();
 _typeStructOnlyMap.freeze();
 _typeTestCase.freeze();
 _typeVomdataStruct.freeze();
@@ -463,6 +484,8 @@
 module.exports.SetOnlyMap = (vdl.registry.lookupOrCreateConstructor(_typeSetOnlyMap));
 module.exports.SetStructMap = (vdl.registry.lookupOrCreateConstructor(_typeSetStructMap));
 module.exports.SometimesSetMap = (vdl.registry.lookupOrCreateConstructor(_typeSometimesSetMap));
+module.exports.StructAny = (vdl.registry.lookupOrCreateConstructor(_typeStructAny));
+module.exports.StructMap = (vdl.registry.lookupOrCreateConstructor(_typeStructMap));
 module.exports.StructOnlyMap = (vdl.registry.lookupOrCreateConstructor(_typeStructOnlyMap));
 module.exports.TestCase = (vdl.registry.lookupOrCreateConstructor(_typeTestCase));
 module.exports.VomdataStruct = (vdl.registry.lookupOrCreateConstructor(_typeVomdataStruct));
@@ -2796,9 +2819,116 @@
   'hexType': "513407001c762e696f2f7632332f766f6d2f74657374646174612e4e556e696f6e01030001410101e10001420103e10001430109e1e1",
   'hexValue': "1c29",
 },
+{
+  'name': "StructAny{}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+  'any': null,
+}, true), _typeStructAny),
+  'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e15201e1",
+  'hexVersion': "80",
+  'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1",
+  'hexValue': "5201e1",
+},
+{
+  'name': "StructAny{Any: false}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+  'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(vdl.types.BOOL))(false, true), vdl.types.BOOL),
+}, true), _typeStructAny),
+  'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e15204000100e1",
+  'hexVersion': "80",
+  'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1",
+  'hexValue': "5204000100e1",
+},
+{
+  'name': "StructAny{Any: StructMap{}}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+  'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+  'map': new Map([]),
+}, true), _typeStructMap),
+}, true), _typeStructAny),
+  'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e15204002ae1e1",
+  'hexVersion': "80",
+  'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e1",
+  'hexValue': "5204002ae1e1",
+},
+{
+  'name': "StructAny{Any: StructMap{Map: {0: 0}}}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+  'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+  'map': new Map([
+  [new vdl.BigInt(0, new Uint8Array([])), new vdl.BigInt(0, new Uint8Array([]))]]),
+}, true), _typeStructMap),
+}, true), _typeStructAny),
+  'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e15208002a00010000e1e1",
+  'hexVersion': "80",
+  'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e1",
+  'hexValue': "5208002a00010000e1e1",
+},
+{
+  'name': "?StructAny(nil)",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))(null, true), _type9),
+  'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae15201e0",
+  'hexVersion': "80",
+  'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae1",
+  'hexValue': "5201e0",
+},
+{
+  'name': "?StructAny{}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+  'any': null,
+}, true), _type9),
+  'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae15201e1",
+  'hexVersion': "80",
+  'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae1",
+  'hexValue': "5201e1",
+},
+{
+  'name': "?StructAny{Any: false}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+  'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(vdl.types.BOOL))(false, true), vdl.types.BOOL),
+}, true), _type9),
+  'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae15204000100e1",
+  'hexVersion': "80",
+  'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae1",
+  'hexValue': "5204000100e1",
+},
+{
+  'name': "?StructAny{Any: StructMap{}}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+  'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+  'map': new Map([]),
+}, true), _typeStructMap),
+}, true), _type9),
+  'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e15204002be1e1",
+  'hexVersion': "80",
+  'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e1",
+  'hexValue': "5204002be1e1",
+},
+{
+  'name': "?StructAny{Any: StructMap{Map: {0: 0}}}",
+  'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+  'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+  'map': new Map([
+  [new vdl.BigInt(0, new Uint8Array([])), new vdl.BigInt(0, new Uint8Array([]))]]),
+}, true), _typeStructMap),
+}, true), _type9),
+  'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+  'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e15208002b00010000e1e1",
+  'hexVersion': "80",
+  'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e1",
+  'hexValue': "5208002b00010000e1e1",
+},
 ], true), _type1);
 
-  module.exports.CompatTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type8))(new Map([
+  module.exports.CompatTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type10))(new Map([
   ["bool", [
 vdl.types.BOOL,
 _typeNBool,
@@ -2819,7 +2949,7 @@
 _typeMapStructSet,
 ]],
   ["number list/array", [
-_type10,
+_type12,
 _typeNArray2Uint64,
 _typeNListUint64,
 ]],
@@ -2846,7 +2976,7 @@
 _typeNComplex128,
 ]],
   ["string list/array", [
-_type11,
+_type13,
 _typeListString,
 _typeArray3String,
 _typeArray4String,
@@ -2875,9 +3005,9 @@
   ["union B", [
 _typeNUnion,
 _typeBdeUnion,
-]]]), true), _type8);
+]]]), true), _type10);
 
-  module.exports.ConvertTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type12))(new Map([
+  module.exports.ConvertTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type14))(new Map([
   ["array/list", [
 {
   'name': "[3]string",
@@ -2888,11 +3018,11 @@
 "B",
 "C",
 ], true), _typeArray3String),
-canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type11))([
+canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type13))([
 "A",
 "B",
 "C",
-], true), _type11),
+], true), _type13),
 ],
 },
 {
@@ -3247,7 +3377,7 @@
 canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeNUnion))({ "a": true }, true), _typeNUnion),
 ],
 },
-]]]), true), _type12);
+]]]), true), _type14);
 
 
 
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
index 5850954..8ff3aad 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
@@ -22,7 +22,6 @@
 
 // Types:
 var _type1 = new vdl.Type();
-var _type10 = new vdl.Type();
 var _type2 = new vdl.Type();
 var _type3 = new vdl.Type();
 var _type4 = new vdl.Type();
@@ -41,9 +40,6 @@
 _type1.kind = vdl.kind.LIST;
 _type1.name = "";
 _type1.elem = _typeRpcCallOption;
-_type10.kind = vdl.kind.LIST;
-_type10.name = "";
-_type10.elem = new principal.BlessingsHandle()._type;
 _type2.kind = vdl.kind.LIST;
 _type2.name = "";
 _type2.elem = new security.BlessingPattern()._type;
@@ -56,19 +52,19 @@
 _type5.kind = vdl.kind.LIST;
 _type5.name = "";
 _type5.elem = new security.Caveat()._type;
-_type6.kind = vdl.kind.OPTIONAL;
+_type6.kind = vdl.kind.LIST;
 _type6.name = "";
-_type6.elem = new principal.JsBlessings()._type;
-_type7.kind = vdl.kind.LIST;
+_type6.elem = vdl.types.STRING;
+_type7.kind = vdl.kind.MAP;
 _type7.name = "";
-_type7.elem = vdl.types.STRING;
-_type8.kind = vdl.kind.MAP;
+_type7.elem = new principal.BlessingsId()._type;
+_type7.key = new security.BlessingPattern()._type;
+_type8.kind = vdl.kind.LIST;
 _type8.name = "";
-_type8.elem = _type6;
-_type8.key = new security.BlessingPattern()._type;
+_type8.elem = new signature.Interface()._type;
 _type9.kind = vdl.kind.LIST;
 _type9.name = "";
-_type9.elem = new signature.Interface()._type;
+_type9.elem = new principal.BlessingsHandle()._type;
 _typeGranterHandle.kind = vdl.kind.INT32;
 _typeGranterHandle.name = "v.io/x/ref/services/wspr/internal/app.GranterHandle";
 _typeGranterRequest.kind = vdl.kind.STRUCT;
@@ -90,7 +86,6 @@
 _typeRpcServerOption.name = "v.io/x/ref/services/wspr/internal/app.RpcServerOption";
 _typeRpcServerOption.fields = [{name: "IsLeaf", type: vdl.types.BOOL}, {name: "ServesMountTable", type: vdl.types.BOOL}];
 _type1.freeze();
-_type10.freeze();
 _type2.freeze();
 _type3.freeze();
 _type4.freeze();
@@ -386,14 +381,9 @@
     },
     ],
     outArgs: [{
-      name: 'publicKeyOut',
+      name: '',
       doc: "",
-      type: vdl.types.STRING
-    },
-    {
-      name: 'handleOut',
-      doc: "",
-      type: new principal.BlessingsHandle()._type
+      type: new principal.BlessingsId()._type
     },
     ],
     inStream: null,
@@ -417,14 +407,9 @@
     },
     ],
     outArgs: [{
-      name: 'publicKeyOut',
+      name: '',
       doc: "",
-      type: vdl.types.STRING
-    },
-    {
-      name: 'handleOut',
-      doc: "",
-      type: new principal.BlessingsHandle()._type
+      type: new principal.BlessingsId()._type
     },
     ],
     inStream: null,
@@ -466,7 +451,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type6
+      type: new principal.BlessingsId()._type
     },
     ],
     inStream: null,
@@ -481,13 +466,13 @@
     inArgs: [{
       name: 'peerBlessings',
       doc: "",
-      type: _type7
+      type: _type6
     },
     ],
     outArgs: [{
       name: '',
       doc: "",
-      type: _type6
+      type: new principal.BlessingsId()._type
     },
     ],
     inStream: null,
@@ -519,7 +504,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type6
+      type: new principal.BlessingsId()._type
     },
     ],
     inStream: null,
@@ -551,7 +536,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type8
+      type: _type7
     },
     ],
     inStream: null,
@@ -593,7 +578,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type7
+      type: _type6
     },
     ],
     inStream: null,
@@ -614,7 +599,7 @@
     outArgs: [{
       name: '',
       doc: "",
-      type: _type9
+      type: _type8
     },
     ],
     inStream: null,
@@ -629,13 +614,13 @@
     inArgs: [{
       name: 'toJoin',
       doc: "",
-      type: _type10
+      type: _type9
     },
     ],
     outArgs: [{
       name: '',
       doc: "",
-      type: _type6
+      type: new principal.BlessingsId()._type
     },
     ],
     inStream: null,
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
index a799f10..f11c056 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
@@ -16,16 +16,39 @@
 
 
 // Types:
+var _typeBlessingsCacheAddMessage = new vdl.Type();
+var _typeBlessingsCacheDeleteMessage = new vdl.Type();
+var _typeBlessingsCacheMessage = new vdl.Type();
 var _typeBlessingsHandle = new vdl.Type();
+var _typeBlessingsId = new vdl.Type();
 var _typeJsBlessings = new vdl.Type();
+_typeBlessingsCacheAddMessage.kind = vdl.kind.STRUCT;
+_typeBlessingsCacheAddMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheAddMessage";
+_typeBlessingsCacheAddMessage.fields = [{name: "CacheId", type: _typeBlessingsId}, {name: "Blessings", type: _typeJsBlessings}];
+_typeBlessingsCacheDeleteMessage.kind = vdl.kind.STRUCT;
+_typeBlessingsCacheDeleteMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheDeleteMessage";
+_typeBlessingsCacheDeleteMessage.fields = [{name: "CacheId", type: _typeBlessingsId}, {name: "DeleteAfter", type: vdl.types.UINT32}];
+_typeBlessingsCacheMessage.kind = vdl.kind.UNION;
+_typeBlessingsCacheMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheMessage";
+_typeBlessingsCacheMessage.fields = [{name: "Add", type: _typeBlessingsCacheAddMessage}, {name: "Delete", type: _typeBlessingsCacheDeleteMessage}];
 _typeBlessingsHandle.kind = vdl.kind.INT32;
 _typeBlessingsHandle.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsHandle";
+_typeBlessingsId.kind = vdl.kind.UINT32;
+_typeBlessingsId.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsId";
 _typeJsBlessings.kind = vdl.kind.STRUCT;
 _typeJsBlessings.name = "v.io/x/ref/services/wspr/internal/principal.JsBlessings";
 _typeJsBlessings.fields = [{name: "Handle", type: _typeBlessingsHandle}, {name: "PublicKey", type: vdl.types.STRING}];
+_typeBlessingsCacheAddMessage.freeze();
+_typeBlessingsCacheDeleteMessage.freeze();
+_typeBlessingsCacheMessage.freeze();
 _typeBlessingsHandle.freeze();
+_typeBlessingsId.freeze();
 _typeJsBlessings.freeze();
+module.exports.BlessingsCacheAddMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheAddMessage));
+module.exports.BlessingsCacheDeleteMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheDeleteMessage));
+module.exports.BlessingsCacheMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheMessage));
 module.exports.BlessingsHandle = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsHandle));
+module.exports.BlessingsId = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsId));
 module.exports.JsBlessings = (vdl.registry.lookupOrCreateConstructor(_typeJsBlessings));
 
 
@@ -44,6 +67,8 @@
 // Services:
 
    
+
+   
  
 
 
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
index b27766f..4d2cfe6 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
@@ -28,7 +28,6 @@
 var _type4 = new vdl.Type();
 var _type5 = new vdl.Type();
 var _type6 = new vdl.Type();
-var _type7 = new vdl.Type();
 var _typeAuthReply = new vdl.Type();
 var _typeCaveatValidationRequest = new vdl.Type();
 var _typeCaveatValidationResponse = new vdl.Type();
@@ -52,12 +51,9 @@
 _type5.kind = vdl.kind.LIST;
 _type5.name = "";
 _type5.elem = vdl.types.ERROR;
-_type6.kind = vdl.kind.OPTIONAL;
+_type6.kind = vdl.kind.LIST;
 _type6.name = "";
-_type6.elem = new principal.JsBlessings()._type;
-_type7.kind = vdl.kind.LIST;
-_type7.name = "";
-_type7.elem = new signature.Interface()._type;
+_type6.elem = new signature.Interface()._type;
 _typeAuthReply.kind = vdl.kind.STRUCT;
 _typeAuthReply.name = "v.io/x/ref/services/wspr/internal/rpc/server.AuthReply";
 _typeAuthReply.fields = [{name: "Err", type: vdl.types.ERROR}];
@@ -72,23 +68,22 @@
 _typeContext.fields = [{name: "Language", type: vdl.types.STRING}];
 _typeLookupReply.kind = vdl.kind.STRUCT;
 _typeLookupReply.name = "v.io/x/ref/services/wspr/internal/rpc/server.LookupReply";
-_typeLookupReply.fields = [{name: "Handle", type: vdl.types.INT32}, {name: "HasAuthorizer", type: vdl.types.BOOL}, {name: "HasGlobber", type: vdl.types.BOOL}, {name: "Signature", type: _type7}, {name: "Err", type: vdl.types.ERROR}];
+_typeLookupReply.fields = [{name: "Handle", type: vdl.types.INT32}, {name: "HasAuthorizer", type: vdl.types.BOOL}, {name: "HasGlobber", type: vdl.types.BOOL}, {name: "Signature", type: _type6}, {name: "Err", type: vdl.types.ERROR}];
 _typeSecurityCall.kind = vdl.kind.STRUCT;
 _typeSecurityCall.name = "v.io/x/ref/services/wspr/internal/rpc/server.SecurityCall";
-_typeSecurityCall.fields = [{name: "Method", type: vdl.types.STRING}, {name: "Suffix", type: vdl.types.STRING}, {name: "MethodTags", type: _type1}, {name: "LocalBlessings", type: new principal.JsBlessings()._type}, {name: "LocalBlessingStrings", type: _type2}, {name: "RemoteBlessings", type: new principal.JsBlessings()._type}, {name: "RemoteBlessingStrings", type: _type2}, {name: "LocalEndpoint", type: vdl.types.STRING}, {name: "RemoteEndpoint", type: vdl.types.STRING}];
+_typeSecurityCall.fields = [{name: "Method", type: vdl.types.STRING}, {name: "Suffix", type: vdl.types.STRING}, {name: "MethodTags", type: _type1}, {name: "LocalBlessings", type: new principal.BlessingsId()._type}, {name: "LocalBlessingStrings", type: _type2}, {name: "RemoteBlessings", type: new principal.BlessingsId()._type}, {name: "RemoteBlessingStrings", type: _type2}, {name: "LocalEndpoint", type: vdl.types.STRING}, {name: "RemoteEndpoint", type: vdl.types.STRING}];
 _typeServerRpcRequest.kind = vdl.kind.STRUCT;
 _typeServerRpcRequest.name = "v.io/x/ref/services/wspr/internal/rpc/server.ServerRpcRequest";
 _typeServerRpcRequest.fields = [{name: "ServerId", type: vdl.types.UINT32}, {name: "Handle", type: vdl.types.INT32}, {name: "Method", type: vdl.types.STRING}, {name: "Args", type: _type1}, {name: "Call", type: _typeServerRpcRequestCall}];
 _typeServerRpcRequestCall.kind = vdl.kind.STRUCT;
 _typeServerRpcRequestCall.name = "v.io/x/ref/services/wspr/internal/rpc/server.ServerRpcRequestCall";
-_typeServerRpcRequestCall.fields = [{name: "SecurityCall", type: _typeSecurityCall}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "Context", type: _typeContext}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "GrantedBlessings", type: _type6}];
+_typeServerRpcRequestCall.fields = [{name: "SecurityCall", type: _typeSecurityCall}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "Context", type: _typeContext}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "GrantedBlessings", type: new principal.BlessingsId()._type}];
 _type1.freeze();
 _type2.freeze();
 _type3.freeze();
 _type4.freeze();
 _type5.freeze();
 _type6.freeze();
-_type7.freeze();
 _typeAuthReply.freeze();
 _typeCaveatValidationRequest.freeze();
 _typeCaveatValidationResponse.freeze();
diff --git a/src/proxy/index.js b/src/proxy/index.js
index cd2fe62..c0751cb 100644
--- a/src/proxy/index.js
+++ b/src/proxy/index.js
@@ -25,6 +25,7 @@
 var ByteStreamMessageWriter = require('../vom/byte-stream-message-writer');
 var ByteArrayMessageReader = require('../vom/byte-array-message-reader');
 var TaskSequence = require('../lib/task-sequence');
+var promiseWhile = require('../lib/async-helper').promiseWhile;
 
 // Cache the service signatures for one hour.
 var SIGNATURE_CACHE_TTL = 3600 * 1000;
@@ -62,15 +63,17 @@
   this.typeDecoder = new TypeDecoder();
   this._messageReader = new ByteStreamMessageReader();
   var proxy = this;
-  this._messageReader.nextMessageType(this.typeDecoder).then(restartTypeReader);
-
-  function restartTypeReader(typeId) {
-    vlog.logger.error('The type stream should not have value message ' +
-                      typeId);
-    return proxy.nextMessageType(proxy.typeDecoder).then(restartTypeReader)
-    .catch(restartTypeReader);
-  }
-
+  this._isOpen = true;
+  promiseWhile(function() {
+    return Promise.resolve(proxy._isOpen);
+  }, function() {
+    return proxy._messageReader.nextMessageType(proxy.typeDecoder)
+    .then(function(typeId) {
+      vlog.logger.error('Unexpected type id ' + typeId);
+    }).catch(function(err) {
+      vlog.logger.error('Type decoder failed' + err + ': ' + err.stack);
+    });
+  });
   this.sequence = new TaskSequence();
   EE.call(this);
 }
@@ -140,6 +143,7 @@
   var proxy = this;
   return decoder.decode().then(function(message) {
     message = unwrap(message);
+    // Type messages are handled by the proxy itself.
     if (messageType === Incoming.TYPE_MESSAGE) {
       proxy._messageReader.addBytes(message);
       return;
@@ -250,6 +254,9 @@
                     Outgoing.TYPE_MESSAGE, null, 0);
 };
 
+Proxy.prototype.cleanup = function() {
+  this._isOpen = false;
+};
 /*
  * Export the module
  */
diff --git a/src/proxy/message-type.js b/src/proxy/message-type.js
index b5cdc3c..33c6261 100644
--- a/src/proxy/message-type.js
+++ b/src/proxy/message-type.js
@@ -18,7 +18,7 @@
     CANCEL: 17, // Cancel an ongoing JS initiated call.
     CAVEAT_VALIDATION_RESPONSE: 21, // Response to a caveat validation request.
     GRANTER_RESPONSE: 22, // Response from a granter
-    TYPE_MESSAGE: 23,
+    TYPE_MESSAGE: 23,  // A type message from javascript.
   },
   Incoming: {
     INVOKE_REQUEST: 3, // Request to invoke a method on a JS server.
@@ -32,6 +32,7 @@
     CAVEAT_VALIDATION_REQUEST: 8, // A request to validate a set of caveats
     LOG_MESSAGE: 9,  // A request to log a message.
     GRANTER_REQUEST: 10, // A request to call a granter
-    TYPE_MESSAGE: 12
+    BLESSINGS_CACHE_MESSAGE: 11, // A request to update the blessings cache
+    TYPE_MESSAGE: 12,  // A type message from go.
   }
 };
diff --git a/src/proxy/nacl.js b/src/proxy/nacl.js
index 5143a93..c144b27 100644
--- a/src/proxy/nacl.js
+++ b/src/proxy/nacl.js
@@ -62,6 +62,7 @@
   var self = this;
   var defaultTimeout = 2000;
   var deferred = new Deferred(cb);
+  this.cleanup();
 
   extensionEventProxy.removeListener('crash', this.onCrash);
 
diff --git a/src/proxy/simple-handler.js b/src/proxy/simple-handler.js
deleted file mode 100644
index 6f9a8e3..0000000
--- a/src/proxy/simple-handler.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/**
- * @fileoverview A simple handler that resolves or rejects a promise
- * on a response from the proxy.
- * @private
- */
-var Incoming = require('./message-type').Incoming;
-var StreamHandler = require('./stream-handler');
-var vError = require('../gen-vdl/v.io/v23/verror');
-
-/**
- * An object that rejects/resolves a promise based on a response
- * from the proxy.
- * @constructor
- * @private
- * @param {Context} cxt
- * @param {Deferred} def the promise to resolve/reject
- * @param {ProxyConnection} proxy the proxy from which to dequeue the handler
- * @param {number} id the flow id of the message
- */
-var Handler = function(ctx, def, proxy, id) {
-  this._ctx = ctx;
-  this._proxy = proxy;
-  this._def = def;
-  this._id = id;
-  if (def.stream) {
-    this._streamHandler = new StreamHandler(ctx, def.stream);
-  }
-
-};
-
-Handler.prototype.handleResponse = function(type, message) {
-  // If there is a stream, let stream handler process it.
-  if (this._streamHandler &&
-    this._streamHandler.handleResponse(type, message)) {
-    return;
-  }
-
-  switch (type) {
-    case Incoming.FINAL_RESPONSE:
-      this._def.resolve(message);
-      break;
-    case Incoming.ERROR_RESPONSE:
-      this._def.reject(message);
-      break;
-    default:
-      this._def.reject(
-        new vError.InternalError(this._ctx,
-                                 ['unknown response type ' + type]));
-  }
-  this._proxy.dequeue(this._id);
-};
-
-module.exports = Handler;
diff --git a/src/proxy/stream-handler.js b/src/proxy/stream-handler.js
index 84e4a14..672890c 100644
--- a/src/proxy/stream-handler.js
+++ b/src/proxy/stream-handler.js
@@ -6,9 +6,9 @@
 var emitStreamError = require('../lib/emit-stream-error');
 var vError = require('../gen-vdl/v.io/v23/verror');
 var SharedContextKeys = require('../runtime/shared-context-keys');
-var Blessings = require('../security/blessings');
-var JsBlessings =
-  require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
+var BlessingsId =
+  require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').BlessingsId;
+var runtimeFromContext = require('../runtime/runtime-from-context');
 var TaskSequence = require('../lib/task-sequence');
 var Promise = require('../lib/promise');
 var vom = require('../vom');
@@ -59,12 +59,16 @@
   }
   var handler = this;
   return vom.decode(data, false, this._typeDecoder).then(function(data) {
-    if (data instanceof JsBlessings) {
-      data = new Blessings(data.handle, data.publicKey,
-                           handler._controller);
-                           data.retain();
+    if (data instanceof BlessingsId) {
+      var runtime = runtimeFromContext(handler._ctx);
+      runtime.blessingsManager.blessingsFromId(data)
+      .then(function(blessings) {
+        blessings.retain();
+        handler._stream._queueRead(blessings);
+      });
+    } else {
+      handler._stream._queueRead(data);
     }
-    handler._stream._queueRead(data);
   }, function(e) {
     emitStreamError(handler._stream,
                     new vError.InternalError(
diff --git a/src/proxy/websocket.js b/src/proxy/websocket.js
index e5df1be..12a7e24 100644
--- a/src/proxy/websocket.js
+++ b/src/proxy/websocket.js
@@ -103,6 +103,7 @@
 
 ProxyConnection.prototype.close = function(cb) {
   var deferred = new Deferred(cb);
+  this.cleanup();
 
   this.getWebSocket().then(close, function(err) {
     // TODO(jasoncampbell): Better error handling around websocket connection
diff --git a/src/rpc/client.js b/src/rpc/client.js
index 8717da0..840b3ae 100644
--- a/src/rpc/client.js
+++ b/src/rpc/client.js
@@ -39,11 +39,12 @@
 var SharedContextKeys = require('../runtime/shared-context-keys');
 var vtrace = require('../vtrace');
 var Blessings = require('../security/blessings');
-var JsBlessings =
-  require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
 var ByteArrayMessageWriter = require('../vom/byte-array-message-writer');
+var BlessingsId =
+  require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').BlessingsId;
 var Encoder = require('../vom/encoder');
 var TaskSequence = require('../lib/task-sequence');
+var runtimeFromContext = require('../runtime/runtime-from-context');
 var vom = require('../vom');
 
 var OutstandingRPC = function(ctx, options, cb) {
@@ -68,37 +69,34 @@
 };
 
 // Helper function to convert an out argument to the given type.
-function convertOutArg(arg, type, controller) {
-  var canonOutArg = arg;
-  var unwrappedArg = unwrap(arg);
-  if (unwrappedArg instanceof JsBlessings) {
-    var res =
-      new Blessings(unwrappedArg.handle, unwrappedArg.publicKey, controller);
-    res.retain();
-    return res;
+function convertOutArg(ctx, arg, type, controller) {
+  if (arg instanceof BlessingsId) {
+    var runtime = runtimeFromContext(ctx);
+    return runtime.blessingsManager.blessingsFromId(arg)
+    .then(function(blessings) {
+      if (blessings) {
+        blessings.retain();
+      }
+      return blessings;
+    });
   }
 
   // There's no protection against bad out args if it's a JSValue.
   // Otherwise, convert to the out arg type to ensure type correctness.
   if (!type.equals(vdl.types.JSVALUE)) {
-    canonOutArg = vdl.canonicalize.reduce(arg, type);
+    try {
+      return Promise.resolve(unwrap(vdl.canonicalize.reduce(arg, type)));
+    } catch(err) {
+      return Promise.reject(err);
+    }
   }
 
-  return unwrap(canonOutArg);
-}
-
-// Helper function to safely convert an out argument.
-// The returned error, if any is useful for a callback.
-function convertOutArgSafe(arg, type, controller) {
-  try {
-    return [undefined, convertOutArg(arg, type, controller)];
-  } catch(err) {
-    return [err, undefined];
-  }
+  return Promise.resolve(unwrap(arg));
 }
 
 OutstandingRPC.prototype.start = function() {
   this._id = this._proxy.nextId();
+  var ctx = this._ctx;
   var self = this;
 
   var cb;
@@ -111,25 +109,25 @@
     cb = function convertToMultiArgs(err, results) { // jshint ignore:line
       // If called from a deferred, the results are undefined.
 
-      // Each out argument should also be unwrapped. (results was []any)
-      results = results ? results.map(function(res, i) {
-        var errOrArg = convertOutArgSafe(res, outArgTypes[i], self._controller);
-        if (errOrArg[0] && !err) {
-          err = errOrArg[0];
-        }
-        return errOrArg[1];
-      }) : [];
+      if (err) {
+        origCb(err);
+        return;
+      }
 
-      // TODO(alexfandrianto): Callbacks seem to be able to get both error and
-      // results, but I think we want to limit it to one or the other.
-      var resultsCopy = results.slice();
-      resultsCopy.unshift(err);
-      origCb.apply(null, resultsCopy);
+      // Each out argument should also be unwrapped. (results was []any)
+      results = results || [];
+      var resultPromises = results.map(function(res, i) {
+        return convertOutArg(ctx, res, outArgTypes[i], self._controller);
+      });
+      Promise.all(resultPromises)
+      .then(function(results) {
+        results.unshift(null);
+        origCb.apply(null, results);
+      }).catch(origCb);
     };
   }
 
   var def = new Deferred(cb);
-  var ctx = this._ctx;
 
   if (!this._cb) {
     // If we are using a promise, strip single args out of the arg array.
@@ -140,26 +138,29 @@
           'Internal error: incorrectly formatted out args in client');
       }
 
+
       // Each out argument should also be unwrapped. (args was []any)
-      var unwrappedArgs = args.map(function(outArg, i) {
-        return convertOutArg(outArg, outArgTypes[i], self._controller);
+      var unwrappedArgPromises = args.map(function(outArg, i) {
+        return convertOutArg(ctx, outArg, outArgTypes[i], self._controller);
       });
 
-      // We expect:
-      // 0 args - return; // NOT return [];
-      // 1 args - return a; // NOT return [a];
-      // 2 args - return [a, b] ;
-      //
-      // Convert the results from array style to the expected return style.
-      // undefined, a, [a, b], [a, b, c] etc
-      switch(unwrappedArgs.length) {
-        case 0:
-          return undefined;
-        case 1:
-          return unwrappedArgs[0];
-        default:
-          return unwrappedArgs;
-      }
+      return Promise.all(unwrappedArgPromises).then(function(unwrappedArgs) {
+        // We expect:
+        // 0 args - return; // NOT return [];
+        // 1 args - return a; // NOT return [a];
+        // 2 args - return [a, b] ;
+        //
+        // Convert the results from array style to the expected return style.
+        // undefined, a, [a, b], [a, b, c] etc
+        switch(unwrappedArgs.length) {
+          case 0:
+            return undefined;
+          case 1:
+            return unwrappedArgs[0];
+          default:
+            return unwrappedArgs;
+        }
+      });
     });
   }
 
diff --git a/src/rpc/create-server-call.js b/src/rpc/create-server-call.js
new file mode 100644
index 0000000..616f787
--- /dev/null
+++ b/src/rpc/create-server-call.js
@@ -0,0 +1,63 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var createSecurityCall = require('../security/create-security-call');
+
+module.exports = createServerCall;
+
+/**
+ * Create a server call object. This exists so that we can resolve blessings
+ * before the user is given the object.
+ * @private
+ */
+function createServerCall(request, blessingsManager) {
+  var serverCall = new ServerCall();
+  if (request instanceof ServerCall) {
+    serverCall.securityCall = request.securityCall.clone();
+    serverCall.grantedBlessings = request.grantedBlessings;
+    return Promise.resolve(serverCall);
+  } else {
+    var promises = [];
+    promises.push(createSecurityCall(request.call.securityCall,
+      blessingsManager).then(function(securityCall) {
+      serverCall.securityCall = securityCall;
+    }));
+    if (request.call.grantedBlessings) {
+      promises.push(
+        blessingsManager.blessingsFromId(request.call.grantedBlessings)
+        .then(function(grantedBlessings) {
+          serverCall.grantedBlessings = grantedBlessings;
+        })
+      );
+    }
+    return Promise.all(promises).then(function() {
+      return serverCall;
+    });
+  }
+}
+
+/**
+ * @summary
+ * A ServerCall is a context.Context subclass that includes additional
+ * information about an ongoing server call.
+ * @description
+ * <p>Private Constructor, an instance of ServerCall is passed to every service
+ * method as the first argument.</p>
+ * @inner
+ * @constructor
+ *
+ * @property {module:vanadium.security~SecurityCall} securityCall The
+ * Security Call for the request.
+ *
+ * @property {module:vanadium.security~Blessings} grantedBlessings The
+ * blessings optionally granted to the server from the client through a
+ * granter.
+ *
+ * @property {*} methodTags The tags attached to the method,
+ * interface specification in VDL.
+ *
+ * @memberof module:vanadium.rpc
+ */
+function ServerCall() {
+}
diff --git a/src/rpc/granter-router.js b/src/rpc/granter-router.js
index dee6e7a..075d46c 100644
--- a/src/rpc/granter-router.js
+++ b/src/rpc/granter-router.js
@@ -12,7 +12,7 @@
 var MessageType = require('../proxy/message-type');
 var Incoming = MessageType.Incoming;
 var Outgoing = MessageType.Outgoing;
-var SecurityCall = require('../security/call');
+var createSecurityCall = require('../security/create-security-call');
 var InspectableFunction = require('../lib/inspectable-function');
 var GranterResponse =
 require('../gen-vdl/v.io/x/ref/services/wspr/internal/app').GranterResponse;
@@ -25,13 +25,14 @@
  * grant requests.
  * @private
  */
-function GranterRouter(proxy, rootCtx) {
+function GranterRouter(proxy, rootCtx, blessingsManager) {
   proxy.addIncomingHandler(Incoming.GRANTER_REQUEST, this);
 
   this._proxy = proxy;
   this._rootCtx = rootCtx;
   this.nextGranterId = 0;
   this.activeGranters = {};
+  this._blessingsManager = blessingsManager;
 }
 
 /**
@@ -54,9 +55,10 @@
   }
 
   var router = this;
+  var granter;
   return vom.decode(request).then(function(request) {
     request = request.val;
-    var granter = router.activeGranters[request.granterHandle];
+    granter = router.activeGranters[request.granterHandle];
     if (!granter) {
       // TODO(bjornick): Pass in context here so we can generate useful error
       // messages
@@ -64,7 +66,11 @@
         new verror.NoExistError(router._rootCtx, 'unknown granter'));
     }
     delete router.activeGranters[request.granterHandle];
-    var securityCall = new SecurityCall(request.call, router._controller);
+    return createSecurityCall(request.call, router._blessingsManager);
+  }, function(e) {
+    return Promise.reject(
+      new verror.NoExistError(router._rootCtx, 'failed to decode message'));
+  }).then(function(securityCall) {
     var ctx = router._rootCtx;
     var inspectFn = new InspectableFunction(granter);
     var resolve;
@@ -81,9 +87,6 @@
                 return resolve(res);
               });
     return promise;
-  }, function(e) {
-    return Promise.reject(
-      new verror.NoExistError(router._rootCtx, 'failed to decode message'));
   }).then(function(outBlessings) {
     var result = new GranterResponse({blessings: outBlessings[0]._id});
     var data = hexVom.encode(result);
diff --git a/src/rpc/server-call.js b/src/rpc/server-call.js
deleted file mode 100644
index ae9401e..0000000
--- a/src/rpc/server-call.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-var SecurityCall = require('../security/call');
-var Blessings = require('../security/blessings');
-
-module.exports = ServerCall;
-
-/**
- * @summary
- * A ServerCall is a context.Context subclass that includes additional
- * information about an ongoing server call.
- * @description
- * <p>Private Constructor, an instance of ServerCall is passed to every service
- * method as the first argument.</p>
- * @inner
- * @constructor
- *
- * @property {module:vanadium.security~SecurityCall} securityCall The
- * Security Call for the request.
- *
- * @property {*} methodTags The tags attached to the method,
- * interface specification in VDL.
- *
- * @memberof module:vanadium.rpc
- */
-function ServerCall(request, controller) {
-  if (!(this instanceof ServerCall)) {
-    return new ServerCall(request, controller);
-  }
-
-  if (request instanceof ServerCall) {
-    this.securityCall = request.securityCall.clone();
-    this.grantedBlessings = request.grantedBlessings;
-  } else {
-    this.securityCall = new SecurityCall(request.call.securityCall,
-                                       controller);
-    if (request.call.grantedBlessings) {
-      this.grantedBlessings = new Blessings(
-        request.call.grantedBlessings.handle,
-        request.call.grantedBlessings.publicKey,
-        controller);
-    }
-  }
-}
diff --git a/src/rpc/server-router.js b/src/rpc/server-router.js
index 82ac8c4..6c4155c 100644
--- a/src/rpc/server-router.js
+++ b/src/rpc/server-router.js
@@ -16,8 +16,8 @@
 var vlog = require('./../lib/vlog');
 var StreamHandler = require('../proxy/stream-handler');
 var verror = require('../gen-vdl/v.io/v23/verror');
-var SecurityCall = require('../security/call');
-var ServerCall = require('./server-call');
+var createSecurityCall = require('../security/create-security-call');
+var createServerCall = require('./create-server-call');
 var vdl = require('../vdl');
 var typeUtil = require('../vdl/type-util');
 var Deferred = require('../lib/deferred');
@@ -37,8 +37,8 @@
 var lib =
   require('../gen-vdl/v.io/x/ref/services/wspr/internal/lib');
 var Blessings = require('../security/blessings');
-var JsBlessings =
-  require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
+var BlessingsId =
+  require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').BlessingsId;
 var WireBlessings =
   require('../gen-vdl/v.io/v23/security').WireBlessings;
 var SharedContextKeys = require('../runtime/shared-context-keys');
@@ -52,7 +52,8 @@
  * @constructor
  * @private
  */
-var Router = function(proxy, appName, rootCtx, controller, caveatRegistry) {
+var Router = function(
+  proxy, appName, rootCtx, controller, caveatRegistry, blessingsManager) {
   this._servers = {};
   this._proxy = proxy;
   this._streamMap = {};
@@ -62,6 +63,7 @@
   this._caveatRegistry = caveatRegistry;
   this._outstandingRequestForId = {};
   this._controller = controller;
+  this._blessingsManager = blessingsManager;
 
   proxy.addIncomingHandler(Incoming.INVOKE_REQUEST, this);
   proxy.addIncomingHandler(Incoming.LOOKUP_REQUEST, this);
@@ -117,11 +119,15 @@
   }
 
   var router = this;
-  var call;
-  vom.decode(request).then(function(request) {
+  var decodedRequest;
+  vom.decode(request).catch(function(e) {
+    return Promise.reject(new verror.InternalError(router._rootCtx,
+      'Failed to decode ', e));
+  }).then(function(req) {
+    decodedRequest = req;
     var ctx = router._rootCtx.withValue(SharedContextKeys.LANG_KEY,
-                                      request.context.language);
-    var server = router._servers[request.serverId];
+                                        decodedRequest.context.language);
+    var server = router._servers[decodedRequest.serverId];
     if (!server) {
       var authReply = new AuthReply({
         // TODO(bjornick): Use the real context
@@ -132,22 +138,20 @@
                                 null, messageId);
       return;
     }
-    call = new SecurityCall(request.call, router._controller);
-
-    return server.handleAuthorization(request.handle, ctx, call);
-  }, function(e) {
-    return Promise.reject(new verror.InternalError(router._rootCtx,
-                                                   'Failed to decode ', e));
+    return createSecurityCall(decodedRequest.call, router._blessingsManager)
+    .then(function(call) {
+      return server.handleAuthorization(decodedRequest.handle, ctx, call);
+    });
   }).then(function() {
     var authReply = new AuthReply({});
     router._proxy.sendRequest(hexVom.encode(authReply),
                               Outgoing.AUTHORIZATION_RESPONSE, null, messageId);
   }).catch(function(e) {
-    var authReply = new AuthReply({
-      err: ErrorConversion.fromNativeValue(e, router._appName,
-                                           call.method)
-    });
-    router._proxy.sendRequest(hexVom.encode(authReply),
+    var errMsg = {
+      err: ErrorConversion.fromNativeValue(e, this._appName,
+                                           decodedRequest.call.method)
+    };
+    router._proxy.sendRequest(hexVom.encode(errMsg),
                               Outgoing.AUTHORIZATION_RESPONSE, null,
                               messageId);
   });
@@ -179,24 +183,24 @@
 };
 
 Router.prototype.handleCaveatValidationRequest = function(messageId, request) {
-  var resultPromises = new Array(request.cavs.length);
-  var call = new SecurityCall(request.call);
-  var ctx = this._rootCtx.withValue(SharedContextKeys.LANG_KEY,
-                                    request.context.language);
-  for (var i = 0; i < request.cavs.length; i++) {
-    resultPromises[i] = this._validateChain(ctx, call, request.cavs[i]);
-  }
-  var self = this;
-  Promise.all(resultPromises).then(function(results) {
-    var response = new CaveatValidationResponse({
-      results: results
+  var router = this;
+  createSecurityCall(request.call, this._blessingsManager)
+  .then(function(call) {
+    var ctx = router._rootCtx.withValue(SharedContextKeys.LANG_KEY,
+      request.context.language);
+    var resultPromises = request.cavs.map(function(cav) {
+      return router._validateChain(ctx, call, cav);
     });
-    self._proxy.sendRequest(hexVom.encode(response),
-                            Outgoing.CAVEAT_VALIDATION_RESPONSE, null,
-                            messageId);
+    return Promise.all(resultPromises).then(function(results) {
+      var response = new CaveatValidationResponse({
+        results: results
+      });
+      var data = hexVom.encode(response);
+      router._proxy.sendRequest(data, Outgoing.CAVEAT_VALIDATION_RESPONSE, null,
+        messageId);
+    });
   }).catch(function(err) {
-    vlog.logger.error(
-      new Error('Unexpected error (all promises should resolve): ' + err));
+    throw new Error('Unexpected error (all promises should resolve): ' + err);
   });
 };
 
@@ -215,24 +219,24 @@
 
   var self = this;
   return server._handleLookup(request.suffix).then(function(value) {
-    var signatureList = value.invoker.signature();
-    var hasAuthorizer = (typeof value.authorizer === 'function');
-    var hasGlobber = value.invoker.hasGlobber();
-    var reply = new LookupReply({
-      handle: value._handle,
-      signature: signatureList,
-      hasAuthorizer: hasAuthorizer,
-      hasGlobber: hasGlobber
-    });
-    self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
-                            null, messageId);
-  }).catch(function(err) {
-    var reply = new LookupReply({
-      err: ErrorConversion.fromNativeValue(err, self._appName, '__Signature')
-    });
-    self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
-                            null, messageId);
-  });
+   var signatureList = value.invoker.signature();
+   var hasAuthorizer = (typeof value.authorizer === 'function');
+   var hasGlobber = value.invoker.hasGlobber();
+   var reply = new LookupReply({
+     handle: value._handle,
+     signature: signatureList,
+     hasAuthorizer: hasAuthorizer,
+     hasGlobber: hasGlobber
+   });
+   self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
+                           null, messageId);
+ }).catch(function(err) {
+   var reply = new LookupReply({
+     err: ErrorConversion.fromNativeValue(err, self._appName, '__Signature')
+   });
+   self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
+                           null, messageId);
+ });
 };
 
 /**
@@ -306,111 +310,118 @@
   var ctx = this.createRPCContext(request);
   var self = this;
   var stream;
-  var call = new ServerCall(request, this._controller);
-  if (request.method === 'Glob__') {
-    if (!invoker.hasGlobber()) {
-      err = new Error('Glob is not implemented');
-      self.sendResult(messageId, 'Glob__', null, err);
-      return;
-    }
-    // Glob takes no streaming input and has GlobReply as output.
-    stream = new Stream(messageId, this._proxy.senderPromise, false,
-      null, naming.GlobReply.prototype._type);
-    this._streamMap[messageId] = stream;
-    this._contextMap[messageId] = ctx;
-    this._outstandingRequestForId[messageId] = 0;
-    this.incrementOutstandingRequestForId(messageId);
-    var globPattern = typeUtil.unwrap(request.args[0]);
-    this.handleGlobRequest(messageId, call.securityCall.suffix,
-                           server, new Glob(globPattern), ctx, call, invoker,
-                           completion);
-    return;
-  }
-
-  function completion() {
-    // There is no results to a glob method.  Everything is sent back
-    // through the stream.
-    self.sendResult(messageId, methodName, null, undefined, 1);
-  }
-
-  // Find the method signature.
-  var signature = invoker.signature();
-  var methodSig;
-  signature.forEach(function(ifaceSig) {
-    ifaceSig.methods.forEach(function(method) {
-      if (method.name === methodName) {
-        methodSig = method;
+  createServerCall(request, this._blessingsManager).then(function(call) {
+    if (request.method === 'Glob__') {
+      if (!invoker.hasGlobber()) {
+        err = new Error('Glob is not implemented');
+        self.sendResult(messageId, 'Glob__', null, err);
+        return;
       }
-    });
-  });
-  if (methodSig === undefined) {
-    err = new verror.NoExistError(
-      call, 'Requested method', methodName, 'not found on');
-    this.sendResult(messageId, methodName, null, err);
-    return;
-  }
-
-  // Unwrap the RPC arguments sent to the JS server.
-  var unwrappedArgs = request.args.map(function(arg, i) {
-    // If an any type was expected, unwrapping is not needed.
-    if (methodSig.inArgs[i].type.kind === vdl.kind.ANY) {
-      return arg;
-    }
-    var unwrapped = typeUtil.unwrap(arg);
-    if (unwrapped instanceof JsBlessings) {
-      return new Blessings(unwrapped.handle, unwrapped.publicKey,
-                           self._controller);
-    }
-    return unwrapped;
-  });
-  var options = {
-    methodName: methodName,
-    args: unwrappedArgs,
-    methodSig: methodSig,
-    ctx: ctx,
-    call: call,
-  };
-
-  this._contextMap[messageId] = options.ctx;
-  if (methodIsStreaming(methodSig)) {
-    var readType = (methodSig.inStream ? methodSig.inStream.type : null);
-    var writeType = (methodSig.outStream ? methodSig.outStream.type : null);
-    stream = new Stream(messageId, this._proxy.senderPromise, false, readType,
-      writeType);
-    this._streamMap[messageId] = stream;
-    var rpc = new StreamHandler(options.ctx, stream);
-    this._proxy.addIncomingStreamHandler(messageId, rpc);
-    options.stream = stream;
-  }
-
-  // Invoke the method;
-  this.invokeMethod(invoker, options, function(err, results) {
-    if (err) {
-      var stackTrace;
-      if (err instanceof Error && err.stack !== undefined) {
-        stackTrace = err.stack;
-      }
-      vlog.logger.debug('Requested method ' + methodName +
-          ' threw an exception on invoke: ', err, stackTrace);
-
-      // The error case has no results; only send the error.
-      self.sendResult(messageId, methodName, undefined, err,
-          methodSig.outArgs.length);
+      // Glob takes no streaming input and has GlobReply as output.
+      stream = new Stream(messageId, self._proxy.senderPromise, false,
+        null, naming.GlobReply.prototype._type);
+      self._streamMap[messageId] = stream;
+      self._contextMap[messageId] = ctx;
+      self._outstandingRequestForId[messageId] = 0;
+      self.incrementOutstandingRequestForId(messageId);
+      var globPattern = typeUtil.unwrap(request.args[0]);
+      self.handleGlobRequest(messageId, call.securityCall.suffix,
+                             server, new Glob(globPattern), ctx, call, invoker,
+                             completion);
       return;
     }
 
-    // Has results; associate the types of the outArgs.
-    var canonResults = results.map(function(result, i) {
-      var t = methodSig.outArgs[i].type;
-      if (t.equals(WireBlessings.prototype._type)) {
-        return result;
-      }
-      return vdl.canonicalize.fill(result, t);
-    });
-    self.sendResult(messageId, methodName, canonResults, undefined,
-                    methodSig.outArgs.length);
-  });
+    function completion() {
+      // There is no results to a glob method.  Everything is sent back
+      // through the stream.
+      self.sendResult(messageId, methodName, null, undefined, 1);
+    }
 
+    // Find the method signature.
+    var signature = invoker.signature();
+    var methodSig;
+    signature.forEach(function(ifaceSig) {
+      ifaceSig.methods.forEach(function(method) {
+        if (method.name === methodName) {
+          methodSig = method;
+        }
+      });
+    });
+    if (methodSig === undefined) {
+      err = new verror.NoExistError(
+        call, 'Requested method', methodName, 'not found on');
+      self.sendResult(messageId, methodName, null, err);
+      return;
+    }
+
+    // Unwrap the RPC arguments sent to the JS server.
+    var unwrappedArgPromises = request.args.map(function(arg, i) {
+      // If an any type was expected, unwrapping is not needed.
+      if (methodSig.inArgs[i].type.kind === vdl.kind.ANY) {
+        return Promise.resolve(arg);
+      }
+      var unwrapped = typeUtil.unwrap(arg);
+      if (unwrapped instanceof BlessingsId) {
+        return self._blessingsManager.blessingsFromId(unwrapped);
+      }
+      return Promise.resolve(unwrapped);
+    });
+
+    return Promise.all(unwrappedArgPromises).then(function(unwrappedArgs) {
+      var options = {
+        methodName: methodName,
+        args: unwrappedArgs,
+        methodSig: methodSig,
+        ctx: ctx,
+        call: call,
+      };
+
+      self._contextMap[messageId] = options.ctx;
+      if (methodIsStreaming(methodSig)) {
+        var readType = (methodSig.inStream ? methodSig.inStream.type : null);
+        var writeType = (methodSig.outStream ? methodSig.outStream.type : null);
+        stream = new Stream(messageId, self._proxy.senderPromise, false,
+          readType, writeType);
+        self._streamMap[messageId] = stream;
+        var rpc = new StreamHandler(options.ctx, stream);
+        self._proxy.addIncomingStreamHandler(messageId, rpc);
+        options.stream = stream;
+      }
+
+      // Invoke the method;
+      self.invokeMethod(invoker, options, function(err, results) {
+        if (err) {
+          var stackTrace;
+          if (err instanceof Error && err.stack !== undefined) {
+            stackTrace = err.stack;
+          }
+          vlog.logger.debug('Requested method ' + methodName +
+              ' threw an exception on invoke: ', err, stackTrace);
+
+          // The error case has no results; only send the error.
+          self.sendResult(messageId, methodName, undefined, err,
+              methodSig.outArgs.length);
+          return;
+        }
+
+        // Has results; associate the types of the outArgs.
+        var canonResults = results.map(function(result, i) {
+          var t = methodSig.outArgs[i].type;
+          if (t.equals(WireBlessings.prototype._type)) {
+            if (!(result instanceof Blessings)) {
+              vlog.logger.error(
+                'Encoding non-blessings value as wire blessings');
+                return null;
+            }
+            return result;
+          }
+          return vdl.canonicalize.fill(result, t);
+        });
+        self.sendResult(messageId, methodName, canonResults, undefined,
+                        methodSig.outArgs.length);
+      });
+    });
+  });
 };
 /**
  * Handles incoming requests from the server to invoke methods on registered
@@ -550,10 +561,13 @@
 
       var suffix = namespaceUtil.join(name, child);
       self.incrementOutstandingRequestForId(messageId);
-      var subCall = new ServerCall(call);
-      subCall.securityCall.suffix = suffix;
       var nextInvoker;
-      server._handleLookup(suffix).then(function(value) {
+      var subCall;
+      createServerCall(call, this._blessingsManager).then(function(servCall) {
+        subCall = servCall;
+        subCall.securityCall.suffix = suffix;
+        return server._handleLookup(suffix);
+      }).then(function(value) {
         nextInvoker = value.invoker;
         return server.handleAuthorization(value._handle, context,
                                           subCall.securityCall);
diff --git a/src/runtime/index.js b/src/runtime/index.js
index 8f4a379..7c51044 100644
--- a/src/runtime/index.js
+++ b/src/runtime/index.js
@@ -23,6 +23,8 @@
 var vtrace = require('../vtrace');
 var Controller =
   require('../gen-vdl/v.io/x/ref/services/wspr/internal/app').Controller;
+var BlessingsManager = require('../security/blessings-manager');
+var BlessingsRouter = require('../security/blessings-router');
 
 module.exports = {
   init: init
@@ -117,6 +119,9 @@
   this._name = options.appName;
   this._language = options.language;
   this.caveatRegistry = new CaveatValidatorRegistry();
+  this.blessingsManager = new BlessingsManager(this._controller);
+  this._blessingsRouter = new BlessingsRouter(this._getProxyConnection(),
+    this.blessingsManager);
 }
 
 inherits(Runtime, EE);
@@ -249,7 +254,8 @@
       this._name,
       this.getContext(),
       this._controller,
-      this.caveatRegistry);
+      this.caveatRegistry,
+      this.blessingsManager);
   }
   return this._router;
 };
@@ -263,7 +269,8 @@
   if (!this._granterRouter) {
     this._granterRouter = new GranterRouter(
       this._getProxyConnection(),
-      this.getContext());
+      this.getContext(),
+      this.blessingsManager);
   }
   return this._granterRouter;
 };
diff --git a/src/security/access/permissions-authorizer.js b/src/security/access/permissions-authorizer.js
index c2a03ad..117b5db 100644
--- a/src/security/access/permissions-authorizer.js
+++ b/src/security/access/permissions-authorizer.js
@@ -12,7 +12,7 @@
 var NoPermissionsError = vdlAccess.NoPermissionsError;
 var Permissions = vdlAccess.Permissions;
 
-module.exports = authorizer;
+module.exports = permissionsAuthorizer;
 var pkgPath = 'v.io/v23/security/access';
 var MultipleTagsError = makeError(
   pkgPath + '.errMultipleMethodTags',
@@ -38,7 +38,7 @@
  * @return {module:vanadium.security.Authorize} An authorizer that applies
  * the perms.
  */
-function authorizer(perms, type) {
+function permissionsAuthorizer(perms, type) {
   // Force the Permissions to have the correct Permissions format.
   var permissions = unwrap(new Permissions(perms));
 
@@ -70,4 +70,4 @@
     }
     return;
   };
-}
\ No newline at end of file
+}
diff --git a/src/security/blessings-cache.js b/src/security/blessings-cache.js
new file mode 100644
index 0000000..e3b0444
--- /dev/null
+++ b/src/security/blessings-cache.js
@@ -0,0 +1,130 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var unwrap = require('../vdl/type-util').unwrap;
+var vlog = require('../lib/vlog');
+var Deferred = require('../lib/deferred');
+
+/**
+ * @fileoverview A cache of blessings, used in conjunction with the cache
+ * in WSPR (principal/cache.go) to reduce the number of times blessings must
+ * be sent across the wire.
+ * This is kept in sync with the WSPR cache.
+ * @private
+ */
+
+module.exports = BlessingsCache;
+
+/**
+ * @summary Cache of blessings received from WSPR.
+ * @description This cache is kept in sync with WSPR to reduce the
+ * number of times that blessings must be sent across the wire.
+ * @constructor
+ * @private
+ */
+function BlessingsCache() {
+ // Each entry has the following fields (which may or may not exist):
+ // - deferredBlessings: a deferred object whose promise resolves to the
+ // blessings
+ // - refCount: number of references to the blessings
+ // - deleteAfter: delete the entry after this number of blessings
+ this._entries = {};
+}
+
+/**
+ * @summary addBlessings adds blessings to the blessings cache.
+ * @param {wspr.internal.principal.BlessingsCacheAddMessage} addMessage
+ */
+BlessingsCache.prototype.addBlessings = function(addMessage) {
+  var id = this._unwrappedId(addMessage.cacheId);
+  var entry = this._getOrCreateEntry(id);
+  entry.deferredBlessings.resolve(addMessage.blessings);
+};
+
+/**
+ * @summary deleteBlessings removes blessings from the blessings cache.
+ * @param {wspr.internal.principal.BlessingsCacheAddMessage} addMessage
+ */
+BlessingsCache.prototype.deleteBlessings = function(deleteMessage) {
+  var id = this._unwrappedId(deleteMessage.cacheId);
+  var entry = this._getOrCreateEntry(id);
+  entry.deleteAfter = deleteMessage.deleteAfter;
+
+  this._deleteIfNoLongerNeeded(id);
+};
+
+/**
+ * @summary blessingsFromId looks up a blessing by id or waits for it if it
+ * has not been put in the cache yet
+ * @param {wspr.internal.principal.BlessingsId} blessingsId
+ */
+BlessingsCache.prototype.blessingsFromId = function(blessingsId) {
+  var id = unwrap(blessingsId);
+
+  if (typeof id !== 'number') {
+    throw new Error('Expected numeric blessings id');
+  }
+  if (id === 0) {
+    // Zero is not a valid id.
+    // TODO(bprosnitz) Replace this with null once we switch to full blessings
+    // objects. It is currently a number because there are no optional numbers
+    // now in VDL.
+    return Promise.resolve(null);
+  }
+
+  var entry = this._getOrCreateEntry(id);
+  var cache = this;
+  return entry.deferredBlessings.promise.then(function(blessings) {
+    cache._increaseRefCount(id);
+    cache._deleteIfNoLongerNeeded(id);
+    return blessings;
+  });
+};
+
+BlessingsCache.prototype._increaseRefCount = function(cacheId) {
+  var entry = this._entries[cacheId];
+  if (!entry) {
+    throw new Error('Unexpectedly got id of missing entry');
+  }
+  entry.refCount++;
+};
+
+BlessingsCache.prototype._deleteIfNoLongerNeeded = function(cacheId) {
+  var entry = this._entries[cacheId];
+  if (!entry) {
+    throw new Error('Entry unexpectedly not present');
+  }
+
+  if (entry.refCount >= entry.deleteAfter) {
+    if (entry.refCount > entry.deleteAfter) {
+      vlog.logger.warn('Got more references than expected');
+    }
+    if (entry.waiting) {
+      vlog.logger.warn(
+        'There should not be anything waiting on entry to be deleted');
+    }
+    delete this._entries[cacheId];
+  }
+};
+
+BlessingsCache.prototype._getOrCreateEntry = function(cacheId) {
+  if (!this._entries[cacheId]) {
+    this._entries[cacheId] = {
+      refCount: 0,
+      deferredBlessings: new Deferred()
+    };
+  }
+  return this._entries[cacheId];
+};
+
+BlessingsCache.prototype._unwrappedId = function(cacheId) {
+  var id = unwrap(cacheId);
+  if (typeof id !== 'number') {
+    throw new Error('Got non-numeric id');
+  }
+  if (id <= 0) {
+    throw new Error('Unexpected non-positive id ' + id);
+  }
+  return id;
+};
diff --git a/src/security/blessings-manager.js b/src/security/blessings-manager.js
new file mode 100644
index 0000000..723b1d7
--- /dev/null
+++ b/src/security/blessings-manager.js
@@ -0,0 +1,49 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/**
+ * @fileoverview Manager of cache blessings. This differs from BlessingsCache
+ * because it converts JsBlessings to Blessings objects.
+ * TODO(bprosnitz) Remove this after switching to performing WireBlessings to
+ * Blessings conversion with native types.
+ * @private
+ */
+
+var BlessingsCache = require('../security/blessings-cache');
+var Blessings = require('../security/blessings');
+
+
+module.exports = BlessingsManager;
+
+/*
+ * TODO(bprosnitz) Replace this with just BlessingsCache after switching
+ * to using native type conversion with blessings.
+ */
+/*
+ * @summary Manager of blessings received from WSPR.
+ * @constructor
+ * @inner
+ */
+function BlessingsManager(controller) {
+  this._blessingsCache = new BlessingsCache();
+  this._controller = controller;
+}
+
+BlessingsManager.prototype.blessingsFromId = function(id) {
+  var controller = this._controller;
+  return this._blessingsCache.blessingsFromId(id).then(function(jsBless) {
+    if (!jsBless) {
+      return null;
+    }
+    return new Blessings(jsBless.handle, jsBless.publicKey, controller);
+  });
+};
+
+BlessingsManager.prototype.addBlessings = function(addMessage) {
+  return this._blessingsCache.addBlessings(addMessage);
+};
+
+BlessingsManager.prototype.deleteBlessings = function(deleteMessage) {
+  return this._blessingsCache.deleteBlessings(deleteMessage);
+};
diff --git a/src/security/blessings-router.js b/src/security/blessings-router.js
new file mode 100644
index 0000000..4254bf9
--- /dev/null
+++ b/src/security/blessings-router.js
@@ -0,0 +1,49 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/**
+ * @fileoveriew A router that handles incoming requests to update the state
+ * of the blessings cache.
+ * @private
+ */
+
+var vlog = require('./../lib/vlog');
+var Incoming = require('../proxy/message-type').Incoming;
+
+module.exports = BlessingsRouter;
+
+/**
+ * A router that handles incoming requests to update the state of the blessings
+ * cache.
+ * @constructor
+ * @private
+ */
+function BlessingsRouter(proxy, blessingsManager) {
+  this._blessingsManager = blessingsManager;
+
+  proxy.addIncomingHandler(Incoming.BLESSINGS_CACHE_MESSAGE, this);
+}
+
+BlessingsRouter.prototype.handleRequest = function(messageId, type, request) {
+  switch (type) {
+  case Incoming.BLESSINGS_CACHE_MESSAGE:
+    this.handleBlessingsCacheMessages(request);
+    return;
+  default:
+    vlog.logger.error('Unknown request type given to blessings router ' + type);
+  }
+};
+
+BlessingsRouter.prototype.handleBlessingsCacheMessages = function(messages) {
+  for (var i = 0; i < messages.length; i++) {
+    var message = messages[i];
+    if (message.hasOwnProperty('add')) {
+      this._blessingsManager.addBlessings(message.add);
+    } else if (message.hasOwnProperty('delete')) {
+      this._blessingsManager.deleteBlessings(message.delete);
+    } else {
+      vlog.logger.error('Unknown blessings cache message: ', message);
+    }
+  }
+};
diff --git a/src/security/blessingstore.js b/src/security/blessingstore.js
index 4ce7a31..ec74dd6 100644
--- a/src/security/blessingstore.js
+++ b/src/security/blessingstore.js
@@ -8,7 +8,7 @@
  */
 
  var Deferred = require('../lib/deferred');
- var Blessings = require('./blessings');
+ var runtimeFromContext = require('../../src/runtime/runtime-from-context');
  var verror = require('../gen-vdl/v.io/v23/verror');
 
  module.exports = BlessingStore;
@@ -185,14 +185,17 @@
    controller.blessingStorePeerBlessings(ctx)
    .then(function(peerBlessings) {
      var outPeerBlessings = new Map();
-     peerBlessings.forEach(function(jsBlessings, pattern) {
-       var blessingObj = new Blessings(
-         jsBlessings.handle,
-         jsBlessings.publicKey,
-         controller);
-       outPeerBlessings.set(pattern, blessingObj);
+     var promises = [];
+     peerBlessings.forEach(function(blessId, pattern) {
+       var runtime = runtimeFromContext(ctx);
+       promises.push(runtime.blessingsManager.blessingsFromId(blessId)
+       .then(function(blessingsObj) {
+         outPeerBlessings.set(pattern, blessingsObj);
+       }));
      });
-     def.resolve(outPeerBlessings);
+     return Promise.all(promises).then(function() {
+       def.resolve(outPeerBlessings);
+     });
    }).catch(function(err) {
      def.reject(err);
    });
diff --git a/src/security/call.js b/src/security/call.js
deleted file mode 100644
index daf095f..0000000
--- a/src/security/call.js
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/**
- * @fileoverview A context passed to the authorizer
- * @private
- */
-var Blessings = require('./blessings.js');
-module.exports = Call;
-
-/**
- * @summary Call defines the state available for authorizing a principal.
- * @name SecurityCall
- * @property {string} method The method being invoked.
- * @property {string} suffix The object name suffix of the request.
- * @property {module:vanadium.security~Blessings} localBlessings The blessings
- * bound to the local end.
- * @property {string} localBlessingStrings The validated names for the local
- * end.
- * @property {module:vanadium.security~Blessings} remoteBlessings The blessings
- * bound to the remote end.
- * @property {string} remoteBlessingStrings The validated names for the remote
- * end.
- * @property {string} localEndpoint The endpoint string for the local end.
- * @property {string} remoteEndpoint The endpoint string for the remote end.
- * @inner
- * @memberof module:vanadium.security
- */
-function Call(call, controller) {
-  this.method = call.method;
-  this.suffix = call.suffix;
-  // TODO(bjornick): Use the enums.
-  this.methodTags = call.methodTags;
-  this.localBlessings = new Blessings(call.localBlessings.handle,
-                                      call.localBlessings.publicKey,
-                                      controller);
-  this.remoteBlessings = new Blessings(call.remoteBlessings.handle,
-                                       call.remoteBlessings.publicKey,
-                                       controller);
-  if (call.grantedBlessings) {
-    this.grantedBlessings = new Blessings(call.grantedBlessings.handle,
-                                          call.grantedBlessings.publicKey,
-                                          controller);
-  }
-  this.localBlessingStrings = call.localBlessingStrings;
-  this.remoteBlessingStrings = call.remoteBlessingStrings;
-  // TODO(bjornick): Create endpoints.
-  this.localEndpoint = call.localEndpoint;
-  this.remoteEndpoint = call.remoteEndpoint;
-}
-
-Call.prototype.clone = function() {
-  var res = Object.create(this.constructor.prototype);
-  Object.defineProperty(res, 'constructor', { value: this.constructor });
-  for (var key in this) {
-    if (!this.hasOwnProperty(key)) {
-      continue;
-    }
-    res[key] = this[key];
-  }
-  return res;
-};
diff --git a/src/security/create-security-call.js b/src/security/create-security-call.js
new file mode 100644
index 0000000..8cdd467
--- /dev/null
+++ b/src/security/create-security-call.js
@@ -0,0 +1,74 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/**
+ * @fileoverview A security information passes to authorizer and validator.
+ * @private
+ */
+module.exports = createSecurityCall;
+
+/**
+ * Create a security call object. This exists so that we can resolve blessings
+ * before the user is given the object.
+ * @private
+ */
+function createSecurityCall(input, blessingsManager) {
+  var call = new Call();
+  call.method = input.method;
+  call.suffix = input.suffix;
+  call.methodTags = input.methodTags;
+  call.localBlessingStrings = input.localBlessingStrings;
+  call.remoteBlessingStrings = input.remoteBlessingStrings;
+  // TODO(bjornick): Create endpoints.
+  call.localEndpoint = input.localEndpoint;
+  call.remoteEndpoint = input.remoteEndpoint;
+
+  var promises = [];
+  promises.push(blessingsManager.blessingsFromId(input.localBlessings)
+  .then(function(localBlessings) {
+    call.localBlessings = localBlessings;
+  }));
+  promises.push(blessingsManager.blessingsFromId(input.remoteBlessings)
+  .then(function(remoteBlessings) {
+    call.remoteBlessings = remoteBlessings;
+    return call;
+  }));
+
+  return Promise.all(promises).then(function() {
+    return call;
+  });
+}
+
+/**
+ * @summary Call defines the state available for authorizing a principal.
+ * @name SecurityCall
+ * @property {string} method The method being invoked.
+ * @property {string} suffix The object name suffix of the request.
+ * @property {module:vanadium.security~Blessings} localBlessings The blessings
+ * bound to the local end.
+ * @property {string} localBlessingStrings The validated names for the local
+ * end.
+ * @property {module:vanadium.security~Blessings} remoteBlessings The blessings
+ * bound to the remote end.
+ * @property {string} remoteBlessingStrings The validated names for the remote
+ * end.
+ * @property {string} localEndpoint The endpoint string for the local end.
+ * @property {string} remoteEndpoint The endpoint string for the remote end.
+ * @inner
+ * @memberof module:vanadium.security
+ */
+function Call() {
+}
+
+Call.prototype.clone = function() {
+  var res = Object.create(this.constructor.prototype);
+  Object.defineProperty(res, 'constructor', { value: this.constructor });
+  for (var key in this) {
+    if (!this.hasOwnProperty(key)) {
+      continue;
+    }
+    res[key] = this[key];
+  }
+  return res;
+};
diff --git a/src/security/default-authorizer.js b/src/security/default-authorizer.js
index a16958f..6a952b4 100644
--- a/src/security/default-authorizer.js
+++ b/src/security/default-authorizer.js
@@ -5,9 +5,9 @@
 var blessingMatches = require('./access/blessing-matching');
 var vError = require('./../gen-vdl/v.io/v23/verror');
 
-module.exports = authorizer;
+module.exports = defaultAuthorizer;
 
-function authorizer(ctx, call, cb) {
+function defaultAuthorizer(ctx, call, cb) {
   // If the remoteBlessings has a public key, and it refers to ourselves
   // (i.e a self rpc), then we always authorize.
   if (call.remoteBlessings.publicKey &&
diff --git a/src/security/principal.js b/src/security/principal.js
index bd69964..afc40cc 100644
--- a/src/security/principal.js
+++ b/src/security/principal.js
@@ -8,7 +8,6 @@
  */
 
 var Deferred = require('../lib/deferred');
-var Blessings = require('./blessings');
 var BlessingStore = require('./blessingstore');
 var verror = require('../gen-vdl/v.io/v23/verror');
 
@@ -81,12 +80,9 @@
 
   var caveats = args.slice(4);
 
-  var controller = this._controller;
   this._controller.bless(ctx, publicKey, blessings._id, extension, caveats)
-  .then(function(res) {
-    var publicKey = res[0];
-    var handle = res[1];
-    def.resolve(new Blessings(handle, publicKey, controller));
+  .then(function(blessings) {
+    def.resolve(blessings);
   }).catch(function(err) {
     def.reject(err);
   });
@@ -121,14 +117,11 @@
 
   var controller = this._controller;
   controller.blessSelf(ctx, name, caveats)
-  .then(function(res) {
-    var publicKey = res[0];
-    var handle = res[1];
-    def.resolve(new Blessings(handle, publicKey, controller));
+  .then(function(blessings) {
+    def.resolve(blessings);
   }).catch(function(err) {
     def.reject(err);
   });
-
   return def.promise;
 };
 
diff --git a/src/vom/type-encoder.js b/src/vom/type-encoder.js
index f951cb8..d74c5e8 100644
--- a/src/vom/type-encoder.js
+++ b/src/vom/type-encoder.js
@@ -27,17 +27,18 @@
  * @constructor
  * @param {module:vanadium.vom.ByteArrayMessageWriter} messageWriter The message
  * writer to write to.
- * @param {function} flusher A function that will be called every time a type
- * message has been written.
+ * @param {function} flush A function that will be called every time a type
+ * message has been written.  An example is to write copy the bytes in
+ * messageWriter to the wire every time a type message is written.
  * @memberof module:vanadium.vom
  */
-function TypeEncoder(messageWriter, flusher) {
+function TypeEncoder(messageWriter, flush) {
   this._typeIds = {};
   // TODO(bjornick): Use the vdl output after we fix:
   // https://github.com/veyron/release-issues/issues/1109
   this._nextId = unwrap(wiretype.WireIdFirstUserType);
   this._messageWriter = messageWriter;
-  this._flusher = flusher;
+  this._flush = flush;
 }
 
 /**
@@ -71,8 +72,8 @@
   var typeId = this._nextId++;
   this._typeIds[stringifiedType] = typeId;
   this._encodeWireType(type, typeId);
-  if (this._flusher) {
-    this._flusher();
+  if (this._flush) {
+    this._flush();
   }
   return typeId;
 };
diff --git a/test/integration/serve.js b/test/integration/serve.js
index 40b8d1c..9d67350 100644
--- a/test/integration/serve.js
+++ b/test/integration/serve.js
@@ -75,7 +75,6 @@
         return callback(err, basicRes);
       }
 
-      console.log('finished with ' + err);
       var ctx = runtime.getContext();
 
       waitUntilResolve();
diff --git a/test/integration/test-authorizer.js b/test/integration/test-authorizer.js
index 895ead4..b8ff575 100644
--- a/test/integration/test-authorizer.js
+++ b/test/integration/test-authorizer.js
@@ -56,10 +56,9 @@
     var ctx = res.runtime.getContext();
     client.bindTo(ctx, 'authorizerTestService/auth').then(function(service) {
       service.call(ctx, 'foo').then(function(value) {
-        assert.error(new Error('call should not have succeeded' + value));
+        assert.error(new Error('call should not have succeeded. res:' + value));
         res.end(assert);
       }).catch(function(err) {
-        // We expect to get to the error case.
         assert.ok(err);
         res.end(assert);
       });
diff --git a/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java b/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java
index 129bf3e..6c5cee5 100644
--- a/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java
+++ b/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java
@@ -11,6 +11,7 @@
 import org.openqa.selenium.chrome.ChromeDriver;
 import org.openqa.selenium.chrome.ChromeDriverService;
 
+import io.v.webdriver.Util;
 import io.v.webdriver.htmlreport.HTMLReportData;
 import io.v.webdriver.commonpages.ChromeSignInPage;
 import io.v.webdriver.commonpages.ExtensionInstallationPage;
@@ -143,5 +144,8 @@
     // Check Vanadium extension option page.
     ExtensionOptionPage extensionOptionPage = new ExtensionOptionPage(driver, reportData);
     extensionOptionPage.go();
+
+    // Wait a little bit to allow the extension to get ready.
+    Util.sleep(5000);
   }
 }
diff --git a/test/unit/test-blessings-cache.js b/test/unit/test-blessings-cache.js
new file mode 100644
index 0000000..1999e3c
--- /dev/null
+++ b/test/unit/test-blessings-cache.js
@@ -0,0 +1,337 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var test = require('prova');
+var BlessingsCache = require('../../src/security/blessings-cache');
+var principal =
+  require('../../src/gen-vdl/v.io/x/ref/services/wspr/internal/principal');
+
+test('Blessing cache - add before use', function(t) {
+  var blessingsA = {
+    publicKey: 'A'
+  };
+  var messages = [
+    {
+      type: 'add',
+      value: {
+        cacheId: 1,
+        blessings: blessingsA
+      }
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 1,
+      expected: blessingsA
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+test('Blessing cache - add after use', function(t) {
+  var blessingsA = {
+    publicKey: 'A'
+  };
+  var messages = [
+    {
+      type: 'blessingsFromId',
+      cacheId: 1,
+      expected: blessingsA
+    },
+    {
+      type: 'add',
+      value: {
+        cacheId: 1,
+        blessings: blessingsA
+      },
+      dontWaitPrevious: true
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+test('Blessing cache - delete after add', function(t) {
+  var blessingsA = {
+    publicKey: 'A'
+  };
+  var messages = [
+    {
+      type: 'add',
+      value: {
+        cacheId: 1,
+        blessings: blessingsA
+      }
+    },
+    {
+      type: 'delete',
+      value: {
+        cacheId: 1,
+        deleteAfter: 0
+      },
+    },
+    {
+      type: 'confirmDelete',
+      cacheId: 1
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+test('Blessing cache - reference counting delete', function(t) {
+  var blessingsA = {
+    publicKey: 'A'
+  };
+  var messages = [
+    {
+      type: 'add',
+      value: {
+        cacheId: 1,
+        blessings: blessingsA
+      }
+    },
+    {
+      type: 'delete',
+      value: {
+        cacheId: 1,
+        deleteAfter: 2
+      },
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 1,
+      expected: blessingsA
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 1,
+      expected: blessingsA
+    },
+    {
+      type: 'confirmDelete',
+      cacheId: 1
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+test('Blessing cache - add after delete', function(t) {
+  var blessingsA = {
+    publicKey: 'A'
+  };
+  var messages = [
+    {
+      type: 'delete',
+      value: {
+        cacheId: 1,
+        deleteAfter: 1
+      },
+    },
+    {
+      type: 'add',
+      value: {
+        cacheId: 1,
+        blessings: blessingsA
+      }
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 1,
+      expected: blessingsA
+    },
+    {
+      type: 'confirmDelete',
+      cacheId: 1
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+test('Blessing cache - multiple entries', function(t) {
+  var blessingsA = {
+    publicKey: 'A'
+  };
+  var blessingsB = {
+    publicKey: 'B'
+  };
+  var blessingsC = {
+    publicKey: 'C'
+  };
+  var messages = [
+    {
+      type: 'add',
+      value: {
+        cacheId: 1,
+        blessings: blessingsA
+      }
+    },
+    {
+      type: 'add',
+      value: {
+        cacheId: 2,
+        blessings: blessingsB
+      }
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 2,
+      expected: blessingsB
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 1,
+      expected: blessingsA
+    },
+    {
+      type: 'delete',
+      value: {
+        cacheId: 1,
+        deleteAfter: 1
+      },
+    },
+    {
+      type: 'confirmDelete',
+      cacheId: 1
+    },
+    {
+      type: 'add',
+      value: {
+        cacheId: 3,
+        blessings: blessingsC
+      }
+    },
+    {
+      type: 'delete',
+      value: {
+        cacheId: 2,
+        deleteAfter: 3
+      },
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 2,
+      expected: blessingsB
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 3,
+      expected: blessingsC
+    },
+    {
+      type: 'delete',
+      value: {
+        cacheId: 3,
+        deleteAfter: 1
+      },
+    },
+    {
+      type: 'confirmDelete',
+      cacheId: 3
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: 2,
+      expected: blessingsB
+    },
+    {
+      type: 'confirmDelete',
+      cacheId: 2
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+test('Blessing cache handles typed BlessingsId objects', function(t) {
+  var blessingsA = {
+    publicKey: 'A'
+  };
+  var messages = [
+    {
+      type: 'add',
+      value: {
+        cacheId: 1,
+        blessings: blessingsA
+      }
+    },
+    {
+      type: 'blessingsFromId',
+      cacheId: new principal.BlessingsId(1),
+      expected: blessingsA
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+test('Blessing cache handles zero blessing id', function(t) {
+  var messages = [
+    {
+      type: 'blessingsFromId',
+      cacheId: new principal.BlessingsId(0),
+      expected: null
+    }
+  ];
+
+  testCache(t, messages);
+});
+
+/**
+ * Tests the cache by handling a sequence of messages.
+ * @private
+ */
+function testCache(t, messages) {
+  var cache = new BlessingsCache();
+  var promises = [];
+  messages.forEach(function(message, index) {
+    // Wait for the previous messages to finish unless dontWaitPrevious is
+    // specified.
+    var preCondPromise = Promise.all(promises);
+    if (message.dontWaitPrevious) {
+      preCondPromise = Promise.resolve();
+    }
+
+    var result = preCondPromise.then(function() {
+      return handleCacheTestMessage(t, cache, message, index);
+    }).catch(function(err) {
+      t.fail('Error in message ' + index + ': ' + err);
+    });
+    promises.push(result);
+  });
+
+  // Wait for all promises to complete.
+  Promise.all(promises).then(function() {
+    t.end();
+  }).catch(function(err) {
+    t.end(err);
+  });
+}
+
+function handleCacheTestMessage(t, cache, message, index) {
+  if (message.type === 'add') {
+    var addMsg = new principal.BlessingsCacheAddMessage(message.value);
+    return cache.addBlessings(addMsg);
+  } else if (message.type === 'delete') {
+    var delMsg = new principal.BlessingsCacheDeleteMessage(message.value);
+    return cache.deleteBlessings(delMsg);
+  } else if (message.type === 'confirmDelete') {
+    t.ok(cache._entries, 'Entries table should exist');
+    t.notOk(message.cacheId in cache._entries,
+      'Cache entry not deleted correctly on message ' + index);
+  } else if (message.type === 'blessingsFromId') {
+    return cache.blessingsFromId(message.cacheId).then(function(blessings) {
+      var expected = null;
+      if (message.expected !== null) {
+        expected = new principal.JsBlessings(message.expected);
+      }
+      t.deepEqual(blessings, expected,
+        'Should get expected blessings on message ' + index);
+    });
+  } else {
+    throw new Error('unknown message type');
+  }
+}
diff --git a/test/unit/test-caveat-validator-registry.js b/test/unit/test-caveat-validator-registry.js
index 67fbf9d..f43a275 100644
--- a/test/unit/test-caveat-validator-registry.js
+++ b/test/unit/test-caveat-validator-registry.js
@@ -6,13 +6,12 @@
 var CaveatValidatorRegistry =
   require('../../src/security/caveat-validator-registry');
 var context = require('../../src/context');
-var SecurityCall = require('../../src/security/call');
 var caveats = require('../../src/security/caveats');
 
 var testCaveats = require('../vdl-out/javascript-test/security/caveat');
 
 function getMockSecurityCall() {
-  return new SecurityCall({
+  return {
     method: '',
     suffix: '',
     methodTags: [],
@@ -28,9 +27,7 @@
     remoteBlessingStrings: [],
     localEndpoint: '',
     remoteEndpoint: ''
-  },
-  null, // controller
-  context.Context());
+  };
 }
 
 
diff --git a/test/unit/test-standard-caveat-validators.js b/test/unit/test-standard-caveat-validators.js
index 0285090..41e545e 100644
--- a/test/unit/test-standard-caveat-validators.js
+++ b/test/unit/test-standard-caveat-validators.js
@@ -8,12 +8,11 @@
 var caveats = require('../../src/security/caveats');
 var vdlSecurity = require('../../src/gen-vdl/v.io/v23/security');
 var context = require('../../src/context');
-var SecurityCall = require('../../src/security/call');
 var Time = require('../../src/gen-vdl/v.io/v23/vdlroot/time').Time;
 var vdl = require('../../src/vdl');
 
 function getMockSecurityCall() {
-  return new SecurityCall({
+  return {
     method: 'aMethod', // only field currently used
     suffix: '',
     methodTags: [],
@@ -29,9 +28,7 @@
     remoteBlessingStrings: [],
     localEndpoint: '',
     remoteEndpoint: ''
-  },
-  null, // controller
-  context.Context());
+  };
 }
 
 function assertValidation(t, cavType, val, cb) {