syncbase: Add transaction type-checks, resolving a couple TODOs

Change-Id: I6a1085dd44e97c1da4f79dbe231eb0b3abae6775
diff --git a/x/ref/services/syncbase/server/db_info.go b/x/ref/services/syncbase/server/db_info.go
index e284fae..3598dd0 100644
--- a/x/ref/services/syncbase/server/db_info.go
+++ b/x/ref/services/syncbase/server/db_info.go
@@ -72,8 +72,8 @@
 // updateDbInfo performs a read-modify-write.
 // fn should "modify" v, and should return a VDL-compatible error.
 // Returns a VDL-compatible error.
-// TODO(sadovsky): Enforce that st is in a transaction.
 func (a *app) updateDbInfo(ctx *context.T, call rpc.ServerCall, st store.StoreReadWriter, dbName string, fn func(info *dbInfo) error) error {
+	_ = st.(store.Transaction) // panics on failure, as desired
 	info, err := a.getDbInfo(ctx, call, st, dbName)
 	if err != nil {
 		return err
diff --git a/x/ref/services/syncbase/server/util/store_util.go b/x/ref/services/syncbase/server/util/store_util.go
index 2201870..69be3c5 100644
--- a/x/ref/services/syncbase/server/util/store_util.go
+++ b/x/ref/services/syncbase/server/util/store_util.go
@@ -94,8 +94,8 @@
 // return a VDL-compatible error.
 // Performs an auth check as part of the "read" step.
 // Returns a VDL-compatible error.
-// TODO(sadovsky): Enforce that st is in a transaction.
 func Update(ctx *context.T, call rpc.ServerCall, st store.StoreReadWriter, l Layer, v Permser, fn func() error) error {
+	_ = st.(store.Transaction) // panics on failure, as desired
 	if err := Get(ctx, call, st, l, v); err != nil {
 		return err
 	}
diff --git a/x/ref/services/syncbase/store/invalid_types.go b/x/ref/services/syncbase/store/invalid_types.go
index 6353a02..7d215b6 100644
--- a/x/ref/services/syncbase/store/invalid_types.go
+++ b/x/ref/services/syncbase/store/invalid_types.go
@@ -6,10 +6,29 @@
 
 // InvalidSnapshot is a store.Snapshot for which all methods return errors.
 type InvalidSnapshot struct {
-	// Error is the error returned by every method call.
-	Error error
+	Error error // returned by all methods
 }
 
+// InvalidStream is a store.Stream for which all methods return errors.
+type InvalidStream struct {
+	Error error // returned by all methods
+}
+
+// InvalidTransaction is a store.Transaction for which all methods return
+// errors.
+type InvalidTransaction struct {
+	Error error // returned by all methods
+}
+
+var (
+	_ Snapshot    = (*InvalidSnapshot)(nil)
+	_ Stream      = (*InvalidStream)(nil)
+	_ Transaction = (*InvalidTransaction)(nil)
+)
+
+////////////////////////////////////////////////////////////
+// InvalidSnapshot
+
 // Close implements the store.Snapshot interface.
 func (s *InvalidSnapshot) Close() error {
 	return WrapError(s.Error)
@@ -25,11 +44,8 @@
 	return &InvalidStream{s.Error}
 }
 
-// InvalidStream is a store.Stream for which all methods return errors.
-type InvalidStream struct {
-	// Error is the error returned by every method call.
-	Error error
-}
+////////////////////////////////////////////////////////////
+// InvalidStream
 
 // Advance implements the store.Stream interface.
 func (s *InvalidStream) Advance() bool {
@@ -55,11 +71,8 @@
 func (s *InvalidStream) Cancel() {
 }
 
-// InvalidTransaction is a store.Transaction for which all methods return errors.
-type InvalidTransaction struct {
-	// Error is the error returned by every method call.
-	Error error
-}
+////////////////////////////////////////////////////////////
+// InvalidTransaction
 
 // ResetForRetry implements the store.Transaction interface.
 func (tx *InvalidTransaction) ResetForRetry() {
diff --git a/x/ref/services/syncbase/store/memstore/stream.go b/x/ref/services/syncbase/store/memstore/stream.go
index 5c5a70b..af4c693 100644
--- a/x/ref/services/syncbase/store/memstore/stream.go
+++ b/x/ref/services/syncbase/store/memstore/stream.go
@@ -46,9 +46,6 @@
 
 // Advance implements the store.Stream interface.
 func (s *stream) Advance() bool {
-	// TODO(sadovsky): Advance should return false and Err should return a non-nil
-	// error if the Store was closed, or if the Snapshot was closed, or if the
-	// Transaction was committed or aborted (or timed out).
 	s.mu.Lock()
 	defer s.mu.Unlock()
 	if s.err != nil {