VOOZH about

URL: https://thenewstack.io/build-your-own-decentralized-twitter-part-2-mitigations/

⇱ Build Your Own Decentralized Twitter, Part 2: Mitigations - The New Stack


TNS
SUBSCRIBE
Join our community of software engineering leaders and aspirational developers. Always stay in-the-know by getting the most important news and exclusive content delivered fresh to your inbox to learn more about at-scale software development.
REQUIRED
It seems that you've previously unsubscribed from our newsletter in the past. Click the button below to open the re-subscribe form in a new tab. When you're done, simply close that tab and continue with this form to complete your subscription.
The New Stack does not sell your information or share it with unaffiliated third parties. By continuing, you agree to our Terms of Use and Privacy Policy.
Welcome and thank you for joining The New Stack community!
Please answer a few simple questions to help us deliver the news and resources you are interested in.
REQUIRED
REQUIRED
REQUIRED
REQUIRED
REQUIRED
Great to meet you!
Tell us a bit about your job so we can cover the topics you find most relevant.
REQUIRED
REQUIRED
REQUIRED
REQUIRED
REQUIRED
Welcome!

We’re so glad you’re here. You can expect all the best TNS content to arrive Monday through Friday to keep you on top of the news and at the top of your game.

What’s next?

Check your inbox for a confirmation email where you can adjust your preferences and even join additional groups.

Follow TNS on your favorite social media networks.

Become a TNS follower on LinkedIn.

Check out the latest featured and trending stories while you wait for your first TNS newsletter.

PREV
1 of 2
NEXT
VOXPOP
As a JavaScript developer, what non-React tools do you use most often?
Angular
0%
Astro
0%
Svelte
0%
Vue.js
0%
Other
0%
I only use React
0%
I don't use JavaScript
0%
Thanks for your opinion! Subscribe below to get the final results, published exclusively in our TNS Update newsletter:
NEW! Try Stackie AI
From clobbered drafts to real-time sync
Apr 14th 2026 10:00am, by David Moore
TypeScript 6.0 RC arrives as a bridge to a faster future
Mar 14th 2026 9:00am, by Darryl K. Taft
Mastra empowers web devs to build AI agents in TypeScript
Jan 28th 2026 11:00am, by Loraine Lawson
2022-12-03 09:07:16
Build Your Own Decentralized Twitter, Part 2: Mitigations
tutorial,
Frontend Development / Open Source

Build Your Own Decentralized Twitter, Part 2: Mitigations

Creating a distributed social media system is all well and good, but how do you address problems like deleted tweets? David Eastman explains.
Dec 3rd, 2022 9:07am by David Eastman
👁 Featued image for: Build Your Own Decentralized Twitter, Part 2: Mitigations
Image via Shutterstock 
In Part 1 of this series, we created an architecture for a distributed social media system, using a Visual Studio code project and corresponding JSON files. Here is the architecture we created:
👁 Image

Our decentralized architecture

The tweet view platform must fetch tweets from the tweeter’s store, based on permission from the platform’s identity files. The key is that the tweeter owns their tweets completely. The Visual Studio code project and corresponding JSON files are here. You can follow along with just the JSON. The purpose of the project is to investigate the issues around a system where ownership and control were firmly in the tweeters’ hands (or beaks). We set everything up in the last article, so read that now and then come back so we can knock it all down. Just as a quick reminder:
  • We use Unix time as both a unique id as well as the time the tweet was made.
  • My replies only lock on to the last tweet — a simplification that saves a lot of code.
  • When playing with the code, don’t forget to change BASEDIRECTORY in JsonServices.cs to match your directory structure.

Name Change

Just as you can on Twitter, you can easily change the name that will be displayed by our tweet view platform without affecting anything else. Alan is tired of his alphabetically convenient username, and decides to change it to “ZoZo” — at least allowing our output format to remain aligned. He changes his Identity in our example tweet view platform:
..
{
 "Id" : 1,
 "Name" : "Zozo",
 "StoreFile" : "AlansTweets.json",
 "Permission" : true
}
..
Running the TweetDisplay gives us: 👁 Image
Because the identity controls the displayed name, not the tweet, everything is fine. Alan can be known as something different on another similar platform. With this architecture, tweeters have no unique identifying name — uniqueness would imply a central controller. Within each tweet view platform, they do at least have a local id. He is ‘1’ — we assume that Alan does not control that internal identifier. Now, we have explicitly not given the platform its own identity (because this is not a federation), so with our architecture, there is no way to ensure that Alan is uniquely identified. Good for anonymity, but also useful for trolls.

No More Alan

Now let’s start the more destructive changes. What happens if Alan stops giving permission to display his tweets?
{
 "Id" : 1,
 "Name" : "Alan",
 "StoreFile" : "AlansTweets.json",
 "Permission" : false
},
TweetDisplay now shows: 👁 Image
While legal, without Alan’s tweets the first thread is damaged. This is not particularly different to a multiple deletion of individual tweets in Twitter. They at least know that there is no simple way to delete all your tweets at once — and they could add friction to the process if they so wished. What extra scaffolding could be erected to at least maintain structure? The tweet platform could replace the deleted tweets with a replica of the same id with the content “[deleted by user].” With that, the platform can assert its right to maintain a structure that the user has broken. But it also proves that an act of deletion took place from the tweeter, so could this betray the tweeter in some extreme circumstances? On further examination, it is really just threads that need this warning — and this is where the structure matters. What we could do as an example mitigation is to add a shadow tweet record when a reply is made to an existing tweet.

Editing

Unlike with Twitter, not only is editing trivial in our project, but you could change every tweet you ever posted as quickly as you can a “search and replace” on a document. Of course this provides for a rather large number of legal problems. At least in Twitter, because you have to delete a tweet before you can change it, the thread is immediately broken. But by editing directly in his tweet store, Alan realises that he can placate Elon Musk rapidly:
[
 {
 "Text": "Hi there, anyone listening?",
 "Replyto": 0,
 "Time": 1668435369
 },
 {
 "Text": "Oh thank god. Hope Jack canu0027t see this",
 "Replyto": 1668435540,
 "Time": 1668438963
 }
]
(Note: in case you hadn’t spotted it, you can’t use an apostrophe in JSON and hence it is escaped in the example above) Immediately this changes the display, because nothing is triggered by a change of content:
👁 Image

Elon changes to Jack

So without any warning, ‘Elon’ has been replaced by ‘Jack’. This would make our model honest to the user’s intent, but absolutely useless as a journal of record. Again, we can mitigate this with an “[edited]” warning.

More Vandalism

As stated in the earlier article, we use the tweeter’s platform identity to link a name to their tweet. That is the main job of the TweetFrom class. We can see that it also implements IComparable in order to allow us to use the tweet Time to compare whether a tweet is younger or older. As mentioned in the first article, the Time variable doubles up as a unique id for a tweet as well as defining the timeline.
<code class="language-json">class TweetFrom : IComparable<TweetFrom>
 {
 public string from;
 public Tweet tweet;

 public TweetFrom(string from, Tweet tweet)
 {
 this.from = from;
 this.tweet = tweet;
 }

 public int CompareTo(TweetFrom? other)
 {
 if (tweet.Time == other?.tweet.Time)
 {
 return 0;
 }

 // CompareTo() method
 return tweet.Time.CompareTo(other?.tweet.Time);
 }
 }</code>
So to list tweets in order, we just call the Sort method on all the TweetFrom objects:
<code class="language-json">...
List<Identity> idents = JsonServices.ReadIdentitesFromFile();
List<TweetFrom> totalTweets = new List<TweetFrom>();
foreach (var ident in idents)
 if (ident.Permission)
 {
 List<Tweet> tweets = JsonServices.ReadTweetsFromFile(ident);
 tweets.ForEach(tweet => totalTweets.Add(new TweetFrom(ident.Name, tweet)));
 }
totalTweets.Sort();
...</code>
With this simple model, a malign tweeter could easily adjust the tweet ids in their own store and thus how the tweet appears in the timeline. So again we are forced to ask, can we easily mitigate for this? We can use internal scaffolding to record the Time that the tweet was first seen by the platform, but this is arbitrary since the tweeter could reveal their tweets at any time.

Mitigations

Mitigation: the action of reducing the severity, seriousness, or painfulness of something. This is exactly what we want to do. We have underlined the weakness of this model, but let’s see how easy it is to address that deletion problem in particular. What we can do is store tweets that have replies, and thus maintain some structure. We don’t have to worry about every tweet, nor content (in fact, we remove this), just the metadata. If you want to see this in code, I’ve used the branch mitigation in the project’s Github entry. The main change in the code is the addition of a new Identity, which we use to store the mitigation tweets. We have also made use of the SortedDictionary so we can mix in our mitigation tweets if they disappear from the graph. Here is our familiar tweet display: 👁 Image
The difference is that we have saved a set of tweets that have replies to them in our new Mitigations internal identity. You can see above that there are four tweets with replies, and they are stored:
[
 {
 "Text": "Tweet not available",
 "Replyto": 0,
 "Time": 1668435369
 },
 {
 "Text": "Tweet not available",
 "Replyto": 1668435369,
 "Time": 1668435540
 },
 {
 "Text": "Tweet not available",
 "Replyto": 0,
 "Time": 1668439104
 },
 {
 "Text": "Tweet not available",
 "Replyto": 1668439104,
 "Time": 1668439185
 }
]
So let’s turn off access to Alan’s tweets (either remove them from his store, or turn off permission in his Identity).
[
 ..
 {
 "Id" : 1,
 "Name" : "Alan",
 "StoreFile" : "AlansTweets.json",
 "Permission" : false
 },
 ..
]
and see the effect: 👁 Image
It is small, but at least you can now see that Beth wasn’t talking to herself. We don’t reveal anything further about the missing tweet, except when it was made. Also, Alan’s tweet at the end of the thread is not replaced as it doesn’t have any replies. I hope I’ve persuaded you that while ‘complete user control’ is perfectly possible, the resulting mayhem may not be very palatable for the social graph. You might well respond that if the platform is in control, it could also vandalize things — but there are many eyes on that. In the final article, we will look a bit closer at federation and how that changes things again.
TRENDING STORIES
David has been a London-based professional software developer with Oracle Corp. and British Telecom, and a consultant helping teams work in a more agile fashion. He wrote a book on UI design and has been writing technical articles ever since....
Read more from David Eastman
SHARE THIS STORY
TRENDING STORIES
SHARE THIS STORY
TRENDING STORIES
TNS DAILY NEWSLETTER Receive a free roundup of the most recent TNS articles in your inbox each day.
The New Stack does not sell your information or share it with unaffiliated third parties. By continuing, you agree to our Terms of Use and Privacy Policy.