---
title: "Challenge #6c: Totally-Available, Read Committed Transactions"
---

# Challenge #6c: Totally-Available, Read Committed Transactions

Now that you have data replicating between nodes from the [Totally-Available, Read Uncommitted Transactions challenge](https://fly.io/dist-sys/6b), we’ll increase the difficulty by strengthening our consistency model to [Read Committed](https://jepsen.io/consistency/models/read-committed).

Read Committed adds consistency guarantees while still being a relatively weak consistency model. In addition to G0, it also prohibits three additional anomalies:

- ***G1a (aborted read):** An aborted transaction T1 writes key x, and a committed transaction T2 reads that write to x.*
- ***G1b (intermediate read):** A committed transaction T2 reads a value of key x that was generated by transaction T1 other than T1’s final write of x.*
- ***G1c (circular information flow):** A cycle of transactions linked by either write-read or read-write dependencies. For instance, transaction T1 writes x = 1 and reads y = 2, and transaction T2 writes y = 2 and reads x = 1*

In summary, these ensure that changes made during a transaction are not visible to other transactions until they are committed.

## Specification

Ensure your distributed key/value store implements a Read Committed consistency model while also preserving total availability.

### Aborting transactions

To test G1a, you can abort a transaction by replying:

```
{
  "type":        "error",
  "in_reply_to": 1,  
  "code":        30,
  "text":        "The requested transaction has been aborted because of a conflict with another transaction. Servers need not return this error on every conflict: they may choose to retry automatically instead."
}
```

The Maelstrom code of `30` is `txn-conflict`. The `in_reply_to` should be the message ID of the request to be aborted.

This can be done with the Go client with:

```
return n.Reply(
    msg,
    map[string]any{
        "type": "error",
        "code": maelstrom.TxnConflict,
        "text": "txn abort",
    },
)
```

## Evaluation

Build your Go binary as `maelstrom-txn` and run it against Maelstrom with the following command:

```
./maelstrom test -w txn-rw-register --bin ~/go/bin/maelstrom-txn --node-count 2 --concurrency 2n --time-limit 20 --rate 1000 --consistency-models read-committed --availability total –-nemesis partition
```

If you’re successful, that’s amazing! You’ve made it to the end of the Fly.io Distributed Systems Challenge. 🎉🎉🎉

If you’re having trouble, jump over to the [Fly.io Community forum](https://community.fly.io/) for help.

If you’ve helped others working on these challenges in the Community forum, we offer our sincere thanks. These are hard topics to wrap our brains around and we all need a hand from time to time.

1. **Echo**
   Get the hang of working with Maelstrom in Go by creating a node which is a binary that receives JSON messages
   
   [Read More About Echo](https://fly.io/dist-sys/1)
2. **Unique ID Generation**
   Implement a globally-unique ID generation system that runs against Maelstrom's unique-ids workload
   
   [Read More About Unique ID Generation](https://fly.io/dist-sys/2)
3. **Broadcast**
   Implement a broadcast system that gossips messages between all nodes in the cluster. Gossiping is a common way
   
   [Read More About Broadcast](https://fly.io/dist-sys/3a)
4. **Grow-Only Counter**
   Implement a stateless, grow-only counter which will run against Maelstrom's g-counter workload. This
   
   [Read More About Grow-Only Counter](https://fly.io/dist-sys/4)
5. **Kafka-Style Log**
   Implement a replicated log service similar to Kafka. Replicated logs are often used as a message bus or
   
   [Read More About Kafka-Style Log](https://fly.io/dist-sys/5a)
6. **Totally-Available Transactions**
   Implement a key/value store which implements transactions. These transactions contain micro-operations
   
   [Read More About Totally-Available Transactions](https://fly.io/dist-sys/6a)
