diff --git a/src/box/xrow.c b/src/box/xrow.c
index 80e74d1979d846653d857873e97354c327b673f8..38f8dc8ea7c2136ff8e1012dfdbe70d1a5cb2e61 100644
--- a/src/box/xrow.c
+++ b/src/box/xrow.c
@@ -523,33 +523,29 @@ iproto_reply_vclock(struct obuf *out, const struct vclock *vclock,
 	return 0;
 }
 
-int
-iproto_reply_vote(struct obuf *out, const struct ballot *ballot,
-		  uint64_t sync, uint64_t schema_version)
+size_t
+mp_sizeof_ballot_max(const struct ballot *ballot)
+{
+	return mp_sizeof_map(1) + mp_sizeof_uint(IPROTO_BALLOT) +
+	       mp_sizeof_map(7) + mp_sizeof_uint(IPROTO_BALLOT_IS_RO_CFG) +
+	       mp_sizeof_bool(ballot->is_ro_cfg) +
+	       mp_sizeof_uint(IPROTO_BALLOT_IS_RO) +
+	       mp_sizeof_bool(ballot->is_ro) +
+	       mp_sizeof_uint(IPROTO_BALLOT_IS_ANON) +
+	       mp_sizeof_bool(ballot->is_anon) +
+	       mp_sizeof_uint(IPROTO_BALLOT_IS_BOOTED) +
+	       mp_sizeof_bool(ballot->is_booted) +
+	       mp_sizeof_uint(IPROTO_BALLOT_VCLOCK) +
+	       mp_sizeof_vclock_ignore0(&ballot->vclock) +
+	       mp_sizeof_uint(IPROTO_BALLOT_GC_VCLOCK) +
+	       mp_sizeof_vclock_ignore0(&ballot->gc_vclock) +
+	       mp_sizeof_uint(IPROTO_BALLOT_CAN_LEAD) +
+	       mp_sizeof_bool(ballot->can_lead);
+}
+
+char *
+mp_encode_ballot(char *data, const struct ballot *ballot)
 {
-	size_t max_size = IPROTO_HEADER_LEN + mp_sizeof_map(1) +
-		mp_sizeof_uint(UINT32_MAX) + mp_sizeof_map(6) +
-		mp_sizeof_uint(UINT32_MAX) + mp_sizeof_bool(ballot->is_ro_cfg) +
-		mp_sizeof_uint(UINT32_MAX) + mp_sizeof_bool(ballot->is_ro) +
-		mp_sizeof_uint(IPROTO_BALLOT_IS_ANON) +
-		mp_sizeof_bool(ballot->is_anon) +
-		mp_sizeof_uint(IPROTO_BALLOT_IS_BOOTED) +
-		mp_sizeof_bool(ballot->is_booted) +
-		mp_sizeof_uint(UINT32_MAX) +
-		mp_sizeof_vclock_ignore0(&ballot->vclock) +
-		mp_sizeof_uint(UINT32_MAX) +
-		mp_sizeof_vclock_ignore0(&ballot->gc_vclock) +
-		mp_sizeof_uint(IPROTO_BALLOT_CAN_LEAD) +
-		mp_sizeof_bool(ballot->can_lead);
-
-	char *buf = obuf_reserve(out, max_size);
-	if (buf == NULL) {
-		diag_set(OutOfMemory, max_size,
-			 "obuf_alloc", "buf");
-		return -1;
-	}
-
-	char *data = buf + IPROTO_HEADER_LEN;
 	data = mp_encode_map(data, 1);
 	data = mp_encode_uint(data, IPROTO_BALLOT);
 	data = mp_encode_map(data, 7);
@@ -567,6 +563,23 @@ iproto_reply_vote(struct obuf *out, const struct ballot *ballot,
 	data = mp_encode_vclock_ignore0(data, &ballot->gc_vclock);
 	data = mp_encode_uint(data, IPROTO_BALLOT_CAN_LEAD);
 	data = mp_encode_bool(data, ballot->can_lead);
+	return data;
+}
+
+int
+iproto_reply_vote(struct obuf *out, const struct ballot *ballot,
+		  uint64_t sync, uint64_t schema_version)
+{
+	size_t max_size = IPROTO_HEADER_LEN + mp_sizeof_ballot_max(ballot);
+
+	char *buf = obuf_reserve(out, max_size);
+	if (buf == NULL) {
+		diag_set(OutOfMemory, max_size, "obuf_alloc", "buf");
+		return -1;
+	}
+
+	char *data = buf + IPROTO_HEADER_LEN;
+	data = mp_encode_ballot(data, ballot);
 	size_t size = data - buf;
 	assert(size <= max_size);
 
diff --git a/src/box/xrow.h b/src/box/xrow.h
index 19e38f4c44524859df89938b6659f3e1e733af36..f03450fb3ed08c80cd24dbfb1ac64d8ac5abf45c 100644
--- a/src/box/xrow.h
+++ b/src/box/xrow.h
@@ -470,6 +470,23 @@ struct ballot {
 	struct vclock gc_vclock;
 };
 
+/**
+ * Calculate the size taken by an encoded ballot.
+ * @param ballot The ballot to estimate the encoded size of.
+ * @retval An upper bound on encoded ballot size.
+ */
+size_t
+mp_sizeof_ballot_max(const struct ballot *ballot);
+
+/**
+ * Encode a ballot to the provided buffer.
+ * @param data Buffer to encode to.
+ * @param ballot Ballot to encode.
+ * @retval A pointer after the end of encoded data.
+ */
+char *
+mp_encode_ballot(char *data, const struct ballot *ballot);
+
 /**
  * Decode ballot response to IPROTO_VOTE from MessagePack.
  * @param row Row to decode.