diff --git a/briar-api/src/net/sf/briar/api/protocol/RetentionAck.java b/briar-api/src/net/sf/briar/api/protocol/RetentionAck.java
index f5e46caae96fd6d16afd873a9a956452d438c017..7b87f0db676df0002461ab18e6d31dab1a1a3977 100644
--- a/briar-api/src/net/sf/briar/api/protocol/RetentionAck.java
+++ b/briar-api/src/net/sf/briar/api/protocol/RetentionAck.java
@@ -9,7 +9,8 @@ public class RetentionAck {
 		this.version = version;
 	}
 
-	public long getVersionNumber() {
+	/** Returns the version number of the acknowledged update. */
+	public long getVersion() {
 		return version;
 	}
 }
diff --git a/briar-api/src/net/sf/briar/api/protocol/RetentionUpdate.java b/briar-api/src/net/sf/briar/api/protocol/RetentionUpdate.java
index 837154cd31153a374a123d5297ea912b1c9f2d92..bdfee3e066d45141c04d3f32ea5caf24258f8846 100644
--- a/briar-api/src/net/sf/briar/api/protocol/RetentionUpdate.java
+++ b/briar-api/src/net/sf/briar/api/protocol/RetentionUpdate.java
@@ -17,7 +17,7 @@ public class RetentionUpdate {
 		return retention;
 	}
 
-	public long getVersionNumber() {
+	public long getVersion() {
 		return version;
 	}
 }
diff --git a/briar-api/src/net/sf/briar/api/protocol/SubscriptionAck.java b/briar-api/src/net/sf/briar/api/protocol/SubscriptionAck.java
index ba2c41a7cf807bcb4f85ea33eb793ccecbd0beb3..caacca97f8a92110a4a93123249108bb8c35f4f3 100644
--- a/briar-api/src/net/sf/briar/api/protocol/SubscriptionAck.java
+++ b/briar-api/src/net/sf/briar/api/protocol/SubscriptionAck.java
@@ -10,7 +10,7 @@ public class SubscriptionAck {
 	}
 
 	/** Returns the version number of the acknowledged update. */
-	public long getVersionNumber() {
+	public long getVersion() {
 		return version;
 	}
 }
diff --git a/briar-api/src/net/sf/briar/api/protocol/SubscriptionUpdate.java b/briar-api/src/net/sf/briar/api/protocol/SubscriptionUpdate.java
index 1e96168f80e16422fc81fe858ff9dd43946d6c39..00e797184fa279c8ada588213127d0a823c76b07 100644
--- a/briar-api/src/net/sf/briar/api/protocol/SubscriptionUpdate.java
+++ b/briar-api/src/net/sf/briar/api/protocol/SubscriptionUpdate.java
@@ -22,7 +22,7 @@ public class SubscriptionUpdate {
 	}
 
 	/** Returns the update's version number. */
-	public long getVersionNumber() {
+	public long getVersion() {
 		return version;
 	}
 }
diff --git a/briar-api/src/net/sf/briar/api/protocol/TransportAck.java b/briar-api/src/net/sf/briar/api/protocol/TransportAck.java
index 11a9dfdc7fb3640281a0e31f2d1f0ec5cd127914..2ccfd9c3611f165323058c2ba9b3e487db764774 100644
--- a/briar-api/src/net/sf/briar/api/protocol/TransportAck.java
+++ b/briar-api/src/net/sf/briar/api/protocol/TransportAck.java
@@ -17,7 +17,7 @@ public class TransportAck {
 	}
 
 	/** Returns the version number of the acknowledged update. */
-	public long getVersionNumber() {
+	public long getVersion() {
 		return version;
 	}
 }
diff --git a/briar-api/src/net/sf/briar/api/protocol/TransportUpdate.java b/briar-api/src/net/sf/briar/api/protocol/TransportUpdate.java
index b4372c4dd8b19ec8382a79cb5071d8606fec5c6c..28e3a4cb1f1e5b10ad69b149b2040c94da64c876 100644
--- a/briar-api/src/net/sf/briar/api/protocol/TransportUpdate.java
+++ b/briar-api/src/net/sf/briar/api/protocol/TransportUpdate.java
@@ -29,7 +29,7 @@ public class TransportUpdate {
 	}
 
 	/** Returns the update's version number. */
-	public long getVersionNumber() {
+	public long getVersion() {
 		return version;
 	}
 }
diff --git a/briar-core/src/net/sf/briar/db/Database.java b/briar-core/src/net/sf/briar/db/Database.java
index 0b16b768eb8af88fd3131753ee9e381adf4f72a6..eaf7b6a143199af17e8d37e05272ef9f51340377 100644
--- a/briar-core/src/net/sf/briar/db/Database.java
+++ b/briar-core/src/net/sf/briar/db/Database.java
@@ -571,8 +571,8 @@ interface Database<T> {
 	 * <p>
 	 * Locking: contact read, transport write.
 	 */
-	void setRemoteProperties(T txn, ContactId c, TransportUpdate u)
-			throws DbException;
+	void setRemoteProperties(T txn, ContactId c, TransportId t,
+			TransportProperties p, long version) throws DbException;
 
 	/**
 	 * Sets the retention time of the given contact's database, unless an
@@ -625,8 +625,8 @@ interface Database<T> {
 	 * <p>
 	 * Locking: contact read, subscription write.
 	 */
-	void setSubscriptions(T txn, ContactId c, SubscriptionUpdate u)
-			throws DbException;
+	void setSubscriptions(T txn, ContactId c, Collection<Group> subs,
+			long version) throws DbException;
 
 	/**
 	 * Records a retention ack from the given contact for the given version
diff --git a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
index 435ae04eddd78b3107b73fa276c3c70d30c347c2..0c96b0fa87fd52bdb7ef4020d9cf5e8429eb8fb4 100644
--- a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
@@ -1207,7 +1207,7 @@ DatabaseCleaner.Callback {
 				try {
 					if(!db.containsContact(txn, c))
 						throw new NoSuchContactException();
-					db.setRetentionUpdateAcked(txn, c, a.getVersionNumber());
+					db.setRetentionUpdateAcked(txn, c, a.getVersion());
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
@@ -1232,7 +1232,7 @@ DatabaseCleaner.Callback {
 					if(!db.containsContact(txn, c))
 						throw new NoSuchContactException();
 					db.setRetentionTime(txn, c, u.getRetentionTime(),
-							u.getVersionNumber());
+							u.getVersion());
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
@@ -1257,7 +1257,7 @@ DatabaseCleaner.Callback {
 				try {
 					if(!db.containsContact(txn, c))
 						throw new NoSuchContactException();
-					db.setSubscriptionUpdateAcked(txn, c, a.getVersionNumber());
+					db.setSubscriptionUpdateAcked(txn, c, a.getVersion());
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
@@ -1281,7 +1281,7 @@ DatabaseCleaner.Callback {
 				try {
 					if(!db.containsContact(txn, c))
 						throw new NoSuchContactException();
-					db.setSubscriptions(txn, c, u);
+					db.setSubscriptions(txn, c, u.getGroups(), u.getVersion());
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
@@ -1309,7 +1309,7 @@ DatabaseCleaner.Callback {
 					TransportId t = a.getId();
 					if(!db.containsTransport(txn, t))
 						throw new NoSuchTransportException();
-					db.setTransportUpdateAcked(txn, c, t, a.getVersionNumber());
+					db.setTransportUpdateAcked(txn, c, t, a.getVersion());
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
@@ -1333,7 +1333,8 @@ DatabaseCleaner.Callback {
 				try {
 					if(!db.containsContact(txn, c))
 						throw new NoSuchContactException();
-					db.setRemoteProperties(txn, c, u);
+					db.setRemoteProperties(txn, c, u.getId(), u.getProperties(),
+							u.getVersion());
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
index 36dffa2d7936e5cdccbffb292e297e979e2dcc6c..c6ba2bb27d9bf463f181ffb1d26bd8ac6c369007 100644
--- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java
+++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
@@ -54,9 +54,52 @@ abstract class JdbcDatabase implements Database<Connection> {
 
 	// Locking: contact
 	private static final String CREATE_CONTACTS =
-			"CREATE TABLE contacts"
-					+ " (contactId COUNTER,"
-					+ " PRIMARY KEY (contactId))";
+			"CREATE TABLE contacts (contactId COUNTER)";
+
+	// Locking: subscription
+	private static final String CREATE_GROUPS =
+			"CREATE TABLE groups"
+					+ " (groupId HASH NOT NULL,"
+					+ " name VARCHAR NOT NULL,"
+					+ " key BINARY," // Null for unrestricted groups
+					+ " PRIMARY KEY (groupId))";
+
+	// Locking: contact read, subscription
+	private static final String CREATE_GROUP_VISIBILITIES =
+			"CREATE TABLE groupVisibilities"
+					+ " (contactId INT NOT NULL,"
+					+ " groupId HASH NOT NULL,"
+					+ " FOREIGN KEY (contactId)"
+					+ " REFERENCES contacts (contactId)"
+					+ " ON DELETE CASCADE,"
+					+ " FOREIGN KEY (groupId)"
+					+ " REFERENCES groups (groupId)"
+					+ " ON DELETE CASCADE)";
+
+	// Locking: contact read, subscription
+	private static final String CREATE_CONTACT_GROUPS =
+			"CREATE TABLE contactGroups"
+					+ " (contactId INT NOT NULL,"
+					+ " groupId HASH NOT NULL," // Not a foreign key
+					+ " name VARCHAR NOT NULL,"
+					+ " key BINARY," // Null for unrestricted groups
+					+ " PRIMARY KEY (contactId, groupId),"
+					+ " FOREIGN KEY (contactId)"
+					+ " REFERENCES contacts (contactId)"
+					+ " ON DELETE CASCADE)";
+
+	// Locking: contact read, subscription
+	private static final String CREATE_GROUP_VERSIONS =
+			"CREATE TABLE groupVersions"
+					+ " (contactId INT NOT NULL,"
+					+ " localVersion BIGINT NOT NULL,"
+					+ " localAcked BIGINT NOT NULL,"
+					+ " remoteVersion BIGINT NOT NULL,"
+					+ " remoteAcked BOOLEAN NOT NULL,"
+					+ " PRIMARY KEY (contactId),"
+					+ " FOREIGN KEY (contactid)"
+					+ " REFERENCES contacts (contactId)"
+					+ " ON DELETE CASCADE)";
 
 	// Locking: message
 	private static final String CREATE_MESSAGES =
@@ -155,56 +198,9 @@ abstract class JdbcDatabase implements Database<Connection> {
 					+ " REFERENCES contacts (contactId)"
 					+ " ON DELETE CASCADE)";
 
-	// Locking: subscription
-	private static final String CREATE_GROUPS =
-			"CREATE TABLE groups"
-					+ " (groupId HASH NOT NULL,"
-					+ " name VARCHAR NOT NULL,"
-					+ " key BINARY," // Null for unrestricted groups
-					+ " PRIMARY KEY (groupId))";
-
-	// Locking: contact read, subscription
-	private static final String CREATE_GROUP_VISIBILITIES =
-			"CREATE TABLE groupVisibilities"
-					+ " (contactId INT NOT NULL,"
-					+ " groupId HASH NOT NULL,"
-					+ " FOREIGN KEY (contactId)"
-					+ " REFERENCES contacts (contactId)"
-					+ " ON DELETE CASCADE,"
-					+ " FOREIGN KEY (groupId)"
-					+ " REFERENCES groups (groupId)"
-					+ " ON DELETE CASCADE)";
-
-	// Locking: contact read, subscription
-	private static final String CREATE_CONTACT_GROUPS =
-			"CREATE TABLE contactGroups"
-					+ " (contactId INT NOT NULL,"
-					+ " groupId HASH NOT NULL," // Not a foreign key
-					+ " name VARCHAR NOT NULL,"
-					+ " key BINARY," // Null for unrestricted groups
-					+ " PRIMARY KEY (contactId, groupId),"
-					+ " FOREIGN KEY (contactId)"
-					+ " REFERENCES contacts (contactId)"
-					+ " ON DELETE CASCADE)";
-
-	// Locking: contact read, subscription
-	private static final String CREATE_GROUP_VERSIONS =
-			"CREATE TABLE groupVersions"
-					+ " (contactId INT NOT NULL,"
-					+ " localVersion BIGINT NOT NULL,"
-					+ " localAcked BIGINT NOT NULL,"
-					+ " remoteVersion BIGINT NOT NULL,"
-					+ " remoteAcked BOOLEAN NOT NULL,"
-					+ " PRIMARY KEY (contactId),"
-					+ " FOREIGN KEY (contactid)"
-					+ " REFERENCES contacts (contactId)"
-					+ " ON DELETE CASCADE)";
-
 	// Locking: transport
 	private static final String CREATE_TRANSPORTS =
-			"CREATE TABLE transports"
-					+ " (transportId HASH NOT NULL,"
-					+ " PRIMARY KEY (transportId))";
+			"CREATE TABLE transports (transportId HASH NOT NULL)";
 
 	// Locking: transport
 	private static final String CREATE_TRANSPORT_CONFIGS =
@@ -355,6 +351,10 @@ abstract class JdbcDatabase implements Database<Connection> {
 		try {
 			s = txn.createStatement();
 			s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
+			s.executeUpdate(insertTypeNames(CREATE_GROUPS));
+			s.executeUpdate(insertTypeNames(CREATE_GROUP_VISIBILITIES));
+			s.executeUpdate(insertTypeNames(CREATE_CONTACT_GROUPS));
+			s.executeUpdate(insertTypeNames(CREATE_GROUP_VERSIONS));
 			s.executeUpdate(insertTypeNames(CREATE_MESSAGES));
 			s.executeUpdate(INDEX_MESSAGES_BY_PARENT);
 			s.executeUpdate(INDEX_MESSAGES_BY_AUTHOR);
@@ -367,10 +367,6 @@ abstract class JdbcDatabase implements Database<Connection> {
 			s.executeUpdate(insertTypeNames(CREATE_FLAGS));
 			s.executeUpdate(insertTypeNames(CREATE_RATINGS));
 			s.executeUpdate(insertTypeNames(CREATE_RETENTION_VERSIONS));
-			s.executeUpdate(insertTypeNames(CREATE_GROUPS));
-			s.executeUpdate(insertTypeNames(CREATE_GROUP_VISIBILITIES));
-			s.executeUpdate(insertTypeNames(CREATE_CONTACT_GROUPS));
-			s.executeUpdate(insertTypeNames(CREATE_GROUP_VERSIONS));
 			s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS));
 			s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_CONFIGS));
 			s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_PROPS));
@@ -832,7 +828,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 					+ " VALUES (?, ?)";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, c.getInt());
-			ps.setBytes(3, g.getBytes());
+			ps.setBytes(2, g.getBytes());
 			int affected = ps.executeUpdate();
 			if(affected != 1) throw new DbStateException();
 			ps.close();
@@ -940,13 +936,11 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT NULL FROM groups AS g"
-					+ " JOIN groupVisibilities AS gv"
-					+ " ON g.groupId = gv.groupId"
-					+ " WHERE g.groupId = ? AND contactId = ?";
+			String sql = "SELECT NULL FROM groupVisibilities"
+					+ " WHERE contactId = ? AND groupId = ?";
 			ps = txn.prepareStatement(sql);
-			ps.setBytes(1, g.getBytes());
-			ps.setInt(2, c.getInt());
+			ps.setInt(1, c.getInt());
+			ps.setBytes(2, g.getBytes());
 			rs = ps.executeQuery();
 			boolean found = rs.next();
 			if(rs.next()) throw new DbStateException();
@@ -1550,7 +1544,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT ct.contactId, ct.transportId, epoch,"
+			String sql = "SELECT e.contactId, e.transportId, epoch,"
 					+ " clockDiff, latency, alice, period, secret, outgoing,"
 					+ " centre, bitmap"
 					+ " FROM endpoints AS e"
@@ -1783,11 +1777,11 @@ abstract class JdbcDatabase implements Database<Connection> {
 		try {
 			String sql = "SELECT g.groupId, name, key, localVersion"
 					+ " FROM groups AS g"
-					+ " JOIN groupVisibilities AS gv"
-					+ " ON g.groupId = gv.groupId"
-					+ " JOIN groupVersions AS v"
-					+ " ON gv.contactId = v.contactId"
-					+ " WHERE gv.contactId = ?"
+					+ " JOIN groupVisibilities AS vis"
+					+ " ON g.groupId = vis.groupId"
+					+ " JOIN groupVersions AS ver"
+					+ " ON vis.contactId = ver.contactId"
+					+ " WHERE vis.contactId = ?"
 					+ " AND localVersion > localAcked";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, c.getInt());
@@ -1971,7 +1965,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 					+ " JOIN groupVisibilities AS gv"
 					+ " ON m.groupId = gv.groupId"
 					+ " AND cg.contactId = gv.contactId"
-					+ " JOIN retentionVersios AS rv"
+					+ " JOIN retentionVersions AS rv"
 					+ " ON cg.contactId = rv.contactId"
 					+ " JOIN statuses AS s"
 					+ " ON m.messageId = s.messageId"
@@ -2461,12 +2455,11 @@ abstract class JdbcDatabase implements Database<Connection> {
 		}
 	}
 
-	public void setRemoteProperties(Connection txn, ContactId c,
-			TransportUpdate u) throws DbException {
+	public void setRemoteProperties(Connection txn, ContactId c, TransportId t,
+			TransportProperties p, long version) throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			TransportId t = u.getId();
 			// Find the existing version, if any
 			String sql = "SELECT remoteVersion FROM contactTransportVersions"
 					+ " WHERE contactId = ? AND transportId = ?";
@@ -2474,12 +2467,12 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps.setInt(1, c.getInt());
 			ps.setBytes(2, t.getBytes());
 			rs = ps.executeQuery();
-			long version = rs.next() ? rs.getLong(1) : -1L;
+			long currentVersion = rs.next() ? rs.getLong(1) : -1L;
 			if(rs.next()) throw new DbStateException();
 			rs.close();
 			ps.close();
 			// Mark the update as needing to be acked
-			if(version == -1L) {
+			if(currentVersion == -1L) {
 				// The row doesn't exist - create it
 				sql = "INSERT INTO contactTransportVersions (contactId,"
 						+ " transportId, remoteVersion, remoteAcked)"
@@ -2487,7 +2480,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 				ps = txn.prepareStatement(sql);
 				ps.setInt(1, c.getInt());
 				ps.setBytes(2, t.getBytes());
-				ps.setLong(3, u.getVersionNumber());
+				ps.setLong(3, version);
 				int affected = ps.executeUpdate();
 				if(affected != 1) throw new DbStateException();
 				ps.close();
@@ -2495,16 +2488,18 @@ abstract class JdbcDatabase implements Database<Connection> {
 				// The row exists - update it
 				sql = "UPDATE contactTransportVersions"
 						+ " SET remoteVersion = ?, remoteAcked = FALSE"
-						+ " WHERE contactId = ? AND transportId = ?";
+						+ " WHERE contactId = ? AND transportId = ?"
+						+ " AND remoteVersion < ?";
 				ps = txn.prepareStatement(sql);
-				ps.setLong(1, Math.max(version, u.getVersionNumber()));
-				ps.setInt(1, c.getInt());
-				ps.setBytes(2, t.getBytes());
+				ps.setLong(1, version);
+				ps.setInt(2, c.getInt());
+				ps.setBytes(3, t.getBytes());
+				ps.setLong(4, version);
 				int affected = ps.executeUpdate();
 				if(affected > 1) throw new DbStateException();
 				ps.close();
 				// Return if the update is obsolete
-				if(u.getVersionNumber() <= version) return;
+				if(version <= currentVersion) return;
 			}
 			// Delete the existing properties, if any
 			sql = "DELETE FROM contactTransportProperties"
@@ -2515,7 +2510,6 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps.executeUpdate();
 			ps.close();
 			// Store the new properties, if any
-			TransportProperties p = u.getProperties();
 			if(p.isEmpty()) return;
 			sql = "INSERT INTO contactTransportProperties"
 					+ " (contactId, transportId, key, value)"
@@ -2524,8 +2518,8 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps.setInt(1, c.getInt());
 			ps.setBytes(2, t.getBytes());
 			for(Entry<String, String> e : p.entrySet()) {
-				ps.setString(1, e.getKey());
-				ps.setString(2, e.getValue());
+				ps.setString(3, e.getKey());
+				ps.setString(4, e.getValue());
 				ps.addBatch();
 			}
 			int[] batchAffected = ps.executeBatch();
@@ -2701,7 +2695,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 	}
 
 	public void setSubscriptions(Connection txn, ContactId c,
-			SubscriptionUpdate u) throws DbException {
+			Collection<Group> subs, long version) throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
@@ -2712,27 +2706,29 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps.setInt(1, c.getInt());
 			rs = ps.executeQuery();
 			if(!rs.next()) throw new DbStateException();
-			long version = rs.getLong(1);
+			long currentVersion = rs.getLong(1);
 			if(rs.next()) throw new DbStateException();
 			rs.close();
 			ps.close();
 			// Mark the update as needing to be acked
 			sql = "UPDATE groupVersions"
 					+ " SET remoteVersion = ?, remoteAcked = FALSE"
-					+ " WHERE contactId = ?";
+					+ " WHERE contactId = ? AND remoteVersion < ?";
 			ps = txn.prepareStatement(sql);
-			ps.setLong(1, Math.max(version, u.getVersionNumber()));
+			ps.setLong(1, version);
 			ps.setInt(2, c.getInt());
+			ps.setLong(3, version);
 			int affected = ps.executeUpdate();
 			if(affected > 1) throw new DbStateException();
 			ps.close();
+			// Return if the update is obsolete
+			if(version <= currentVersion) return;
 			// Delete the existing subscriptions, if any
 			sql = "DELETE FROM contactGroups WHERE contactId = ?";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, c.getInt());
 			ps.executeUpdate();
 			// Store the new subscriptions, if any
-			Collection<Group> subs = u.getGroups();
 			if(subs.isEmpty()) return;
 			sql = "INSERT INTO contactGroups (contactId, groupId, name, key)"
 					+ " VALUES (?, ?, ?, ?)";
diff --git a/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java b/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java
index 3e3f2e04c59f125e44be35c4670c9e62f0acad35..3a9a813fa0d8c2552e99f593308a843f29e82832 100644
--- a/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java
+++ b/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java
@@ -109,20 +109,20 @@ class ProtocolWriterImpl implements ProtocolWriter {
 
 	public void writeRetentionAck(RetentionAck a) throws IOException {
 		w.writeStructId(RETENTION_ACK);
-		w.writeInt64(a.getVersionNumber());
+		w.writeInt64(a.getVersion());
 		if(flush) out.flush();
 	}
 
 	public void writeRetentionUpdate(RetentionUpdate u) throws IOException {
 		w.writeStructId(RETENTION_UPDATE);
 		w.writeInt64(u.getRetentionTime());
-		w.writeInt64(u.getVersionNumber());
+		w.writeInt64(u.getVersion());
 		if(flush) out.flush();
 	}
 
 	public void writeSubscriptionAck(SubscriptionAck a) throws IOException {
 		w.writeStructId(SUBSCRIPTION_ACK);
-		w.writeInt64(a.getVersionNumber());
+		w.writeInt64(a.getVersion());
 		if(flush) out.flush();
 	}
 
@@ -138,14 +138,14 @@ class ProtocolWriterImpl implements ProtocolWriter {
 			else w.writeBytes(publicKey);
 		}
 		w.writeListEnd();
-		w.writeInt64(u.getVersionNumber());
+		w.writeInt64(u.getVersion());
 		if(flush) out.flush();
 	}
 
 	public void writeTransportAck(TransportAck a) throws IOException {
 		w.writeStructId(TRANSPORT_ACK);
 		w.writeBytes(a.getId().getBytes());
-		w.writeInt64(a.getVersionNumber());
+		w.writeInt64(a.getVersion());
 		if(flush) out.flush();
 	}
 
@@ -153,7 +153,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
 		w.writeStructId(TRANSPORT_UPDATE);
 		w.writeBytes(u.getId().getBytes());
 		w.writeMap(u.getProperties());
-		w.writeInt64(u.getVersionNumber());
+		w.writeInt64(u.getVersion());
 		if(flush) out.flush();
 	}
 
diff --git a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
index 18802f9be4416675c719a9fc45becc85d895a038..abca57ba327544495e69b8178ac498dbb5115633 100644
--- a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
@@ -12,7 +12,6 @@ import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Map;
 import java.util.Random;
 
 import net.sf.briar.api.ContactId;
@@ -32,10 +31,7 @@ import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriter;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
 import net.sf.briar.api.protocol.Request;
-import net.sf.briar.api.protocol.Subscription;
-import net.sf.briar.api.protocol.SubscriptionHole;
 import net.sf.briar.api.protocol.SubscriptionUpdate;
-import net.sf.briar.api.protocol.Transport;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.protocol.UnverifiedMessage;
diff --git a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
index 448f0879cbb7da802e48af2e8fd7b09f7801ade7..e4c108d89c939cb1af5328771c889ee533f8dedd 100644
--- a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
+++ b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
@@ -17,9 +17,9 @@ import net.sf.briar.api.db.NoSuchTransportException;
 import net.sf.briar.api.db.event.ContactAddedEvent;
 import net.sf.briar.api.db.event.ContactRemovedEvent;
 import net.sf.briar.api.db.event.DatabaseListener;
+import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
 import net.sf.briar.api.db.event.MessageAddedEvent;
 import net.sf.briar.api.db.event.RatingChangedEvent;
-import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
 import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.AuthorId;
@@ -30,7 +30,6 @@ import net.sf.briar.api.protocol.MessageId;
 import net.sf.briar.api.protocol.Offer;
 import net.sf.briar.api.protocol.Request;
 import net.sf.briar.api.protocol.SubscriptionUpdate;
-import net.sf.briar.api.protocol.Transport;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.transport.Endpoint;
diff --git a/briar-tests/src/net/sf/briar/protocol/ProtocolWriterImplTest.java b/briar-tests/src/net/sf/briar/protocol/ProtocolWriterImplTest.java
index b89b9209d14ff5603a453603baa4b904af5be379..7e842171790addce32e12200755ba47a7db3d3fd 100644
--- a/briar-tests/src/net/sf/briar/protocol/ProtocolWriterImplTest.java
+++ b/briar-tests/src/net/sf/briar/protocol/ProtocolWriterImplTest.java
@@ -52,9 +52,9 @@ public class ProtocolWriterImplTest extends BriarTestCase {
 		b.set(12);
 		b.set(15);
 		w.writeRequest(new Request(b, 16));
-		// Short user tag 6, 0 as uint7, short bytes with length 2, 0xD959
+		// Short user tag 5, 0 as uint7, short bytes with length 2, 0xD959
 		byte[] output = out.toByteArray();
-		assertEquals("C6" + "00" + "92" + "D959",
+		assertEquals("C5" + "00" + "92" + "D959",
 				StringUtils.toHexString(output));
 	}
 
@@ -75,9 +75,9 @@ public class ProtocolWriterImplTest extends BriarTestCase {
 		b.set(11);
 		b.set(12);
 		w.writeRequest(new Request(b, 13));
-		// Short user tag 6, 3 as uint7, short bytes with length 2, 0x59D8
+		// Short user tag 5, 3 as uint7, short bytes with length 2, 0x59D8
 		byte[] output = out.toByteArray();
-		assertEquals("C6" + "03" + "92" + "59D8",
+		assertEquals("C5" + "03" + "92" + "59D8",
 				StringUtils.toHexString(output));
 	}
 }
diff --git a/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java
index f59486243b5a262104b827ef399d6f9458ed0e01..065be0db1335b31a7a312b08ffe7aa44e95af434 100644
--- a/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java
@@ -21,7 +21,6 @@ import net.sf.briar.api.protocol.MessageFactory;
 import net.sf.briar.api.protocol.MessageVerifier;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
-import net.sf.briar.api.protocol.Transport;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.transport.ConnectionContext;