This article isn’t about cryptocurrency or decentralized finance. Instead, we’ll explore public EVM blockchains and how they can be used in your next project, depending on your specific needs and goals. I’ll dive into the pros, cons, and practical examples, using the 0xweb library that I’ve been working on.
§ pro et contra
• 🚀 Zero setup time
It is already up and running. Simply define your data model as a contract and deploy it.
• ✨ Zero maintenance
Once your data is uploaded, it remains accessible as long as the blockchain operates. I can assume that it will be far longer than your other hosting subscription.
• 💯 100% Read uptime; close to 100% Write uptime
The separation of reading and writing processes in blockchain ensures 100% uptime for read operations, especially when leveraging multiple RPC providers for redundancy.
• 🛡️ Secure
Blockchains inherently provide a higher level of security than conventional hosting solutions. Data exploits are possible only if vulnerabilities exist in your data model’s logic.
• 📖 Open Data
Unless encrypted, your data remains open, accessible, and verifiable by anyone, promoting transparency.
• 🖧 DNS-Free
Domain names are unnecessary for this type of backend. Instead, a list of decentralized node providers can be used, allowing client libraries to select the most efficient option for end-users.
• 🤝 Trust
Thanks to the features above, blockchain-based backends inherently build user trust by ensuring data security and 24/7 availability, even if project maintenance and development stops.
• 🧩 Interepolibility with 3rd party data models
You can integrate other data models stored on the blockchain, or other projects can build upon your data model.
• ⚙️ Extensibility
Users can leverage numerous third-party projects to monitor or automate actions, significantly expanding the possibilities of your data model.
• 📜 History and time-travel
The data can be accessed from any point in the past.
• 📡 Events and event-streams
Load historical custom events or use WebSockets to listen for real-time incoming events, enabling dynamic application responses.
• 👤 Built-in user identity
The “wallet” concept enables users to authenticate themselves by signing messages, providing seamless and decentralized user identification.
• 📝 Grant users to modify or extend data
Users can modify or extend data in your storage based on the permissions you define. Importantly, the costs of these modifications are borne by the users themselves. By selecting a low-cost blockchain, these fees can remain negligible, often amounting to only a few cents per transaction.
• 🌐 Huge and continuously evolving ecosystem
- numerous solidity modules you can use to enhance your data model’s functionality.
- many open-source and free services, as well as those offering free plans, are available. It is a common practice within the blockchain community to provide free plans that are often sufficient for production needs.
§ contra
• 💾 Storage is expensive 😢
Though it follows a true pay-as-you-go model, you pay just for the SLOTs you store in. Each SLOT has 32 bytes, it costs 20000 GAS to write new data or 5000 GAS to update the data. Let’s take Polygon as an example, with a 30-gwei GAS price and a $0.60 POL price.
20000GAS × 30gwei = 0.008 POL × $0.60 = $0.00032
This is a lot, so the “Floppy Disk“ emoji represents the storage amounts in the best way, which means it is best suited for smaller datasets if you pay on your own. However, a unique advantage is that users can bear the costs of their own storage and actions, a feature not found in other technologies. While this approach might hinder the mass adoption of your app, it is widely accepted within the blockchain community.
• 🧮 Computation is limited 😢
Blockchain data models support functions for interacting with the data, but their computational capabilities have constraints. These limitations depend on the RPC nodes you use for read actions and the strict GAS limits imposed on write actions (transactions). While basic operations, loops, and deeper call stacks are typically manageable, the blockchain is unsuited for heavy computational workloads.
That said, given the relatively small data sizes typically involved, the existing limits are usually sufficient for most use cases.
§ punctum neutrum
• 🧬 Data structure, Solidity language, SDKs
If you’re new to blockchain development, you may have heard that it’s complicated and hard to get started with. However, this is not true. Blockchain development uses familiar concepts, semantics, and syntax, making it easier to learn than it might seem.
§ Demo: Application Version Repository
https://github.com/0xweb-org/examples-backend
For this article, let’s create an application version manager contract. Imagine you have a desktop application that requires a backend to check for new versions and retrieve the download link whenever a new version is published. Below is the final contract, demonstrating most of the key concepts:
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
struct Package {
uint version;
uint timestamp;
string url;
bytes32 sha256;
}
contract AppVersionManager is Ownable {
// Events that are emitted on data updates
event NewApplicationInfo();
event NewPackage(uint version, uint timestamp);
// Custom error, when title for the application is empty
error TitleIsEmpty();
// Some application information
string public title;
// @TODO: add further application related properties if required
// Latest package
Package public package;
// Track all versions and their packages
mapping (uint => Package) public packages;
// List of all previous versions
uint[] public versions;
constructor () Ownable(msg.sender) {
}
function updateInfo(string calldata newTitle) external onlyOwner {
if (bytes(newTitle).length == 0) {
revert TitleIsEmpty();
}
title = newTitle;
emit NewApplicationInfo();
}
function updatePackage(Package calldata newPackage) external onlyOwner {
require(newPackage.version > package.version, "Newer package already published");
packages[package.version] = package;
package = newPackage;
versions.push(package.version);
emit NewPackage(package.version, block.timestamp);
}
function findPackageAtTimestamp (uint timestamp) external view returns (Package memory) {
if (package.timestamp <= timestamp) {
return package;
}
// the countdown loop to find the latest package for the timestamp
int i = int(versions.length);
while (--i > -1) {
Package memory pkg = packages[versions[uint(i)]];
if (pkg.timestamp <= timestamp) {
return pkg;
}
}
revert("No package found");
}
function getPackage (uint version) external view returns (Package memory) {
if (version == package.version) {
return package;
}
return packages[version];
}
}
Every developer can read and understand this code with minimal effort. If you’re familiar with TypeScript, most of the concepts here will already make sense. To make it even clearer, I’ve created an equivalent TypeScript example: AppVersionManager.ts 🔗.
In simple terms, a contract in Solidity can be thought of as a stateful class instance. The concepts of properties, methods, types, and inheritance are already well-known in object-oriented programming. The main concept to explain here is the onlyOwner
modifier (similar to a decorator in TypeScript).
Every blockchain account is essentially a pair of private and public keys. The account’s ID, known as the address, is derived from the public key. When a transaction is executed, the sender’s address is passed as msg.sender
. Using this, we can store your address in the constructor (during contract deployment). , the onlyOwner
modifier ensures that only you, as the contract owner, can execute the updateInfo
and updatePackage
functions. If someone else attempts these actions, the transaction will be reverted. The onlyOwner
modifier is provided by the Ownable
contract, which is part of the widely-used OpenZeppelin library. This library includes many other useful contracts to streamline blockchain development.
Another important topic to discuss is the concept of Proxies, which split storage and implementation into two separate contracts. Contract implementations in Solidity are immutable, meaning you cannot add new functions or properties after deployment. To work around this, you can deploy a “Proxy” contract. The Proxy handles storage and contains only one fallback
function, which delegates calls to the implementation contract while maintaining the storage context of the Proxy.
This concept may sound complex, but it’s similar to how this
works in JavaScript. Here’s a quick analogy to help clarify:
const foo = new Proxy({ bar: 'Lorem' }, {
get (obj, prop) {
return fooImplementation[prop].bind(obj)
},
});
const fooImplementation = { logValue () { console.log('Bar value:', this.bar) } }
foo.logValue();
The proxy contract holds a reference to the implementation contract. If you want to add new functions, you simply deploy a new implementation contract and update the proxy to reference this new contract, forwarding function calls to the updated instance. It’s a straightforward process, but there’s an edge case to consider: constructors.
When deploying an implementation contract, its constructor operates within the storage of the implementation contract itself. This means that setters like title = "Hello World"
will not modify the proxy’s storage. To address this, we use the initializer function concept:
- Deploy the implementation contract with a
initialize
function. - Deploy the proxy contract, passing the address of the implementation contract in its constructor. This setup allows the
initialize
method to be called in the context of the proxy contract.
As a result, updating the title
property, for example, will correctly update it in the proxy’s storage.
Here’s an upgraded implementation version of our AppVersionManager: AppVersionManagerUpgradeable.sol.
The proxy contract itself is quite universal and independent of the implementation. Several well-known standards for proxies are available in the OpenZeppelin library.
With the knowledge of these concepts and the examples above, you’re ready to develop smart contracts for your business cases.
§ Deployment
- Select the blockchain
First, we need to select the blockchain where we want to deploy our contract. For this example, I’ve chosen Polygon. It offers low transaction costs, has been around for a long time, and has consistently performed well. Its stable and efficient infrastructure, combined with a Total Value Locked (TVL) of $0.9 billion, makes it a reliable choice. Deploying your contracts to public blockchains means coexisting with financial institutions. The TVL metric reflects the trust these institutions place in the blockchain’s reliability.
Moreover, if conditions change, you can always redeploy the contract to another blockchain in the future.
- Deploy
The demo project also serves as the CI test repository, so all the commands can be found here: https://github.com/0xweb-org/examples-backend/blob/master/deploy-cli.sh
# Install 0xweb library from NPM into the prject folder
npm i 0xweb
# Install required dependencies to compile/deploy *.sol files
npx 0xweb init --hardhat --openzeppelin
# Create or import the account. Private key will be encrypted with pin AND machine key.
npx 0xweb accounts new --name foo --pin test --login
# Save the private key securly and ensure the account has some POL tokens
# Deploy. The foo account is selected as default.
npx 0xweb deploy ./contracts/AppVersionManager.sol --chain polygon --pin test
# Set title
npx 0xweb c write AppVersionManager updateInfo --newTitle MySuperApp --pin test
# Set latest package information
npx 0xweb c write AppVersionManager updatePackage --arg0 'load(./data/package.json)' --pin test
With just a few commands, you’ve deployed the contract and updated the data. That’s it for the backend—it’s now up and running “forever” without requiring any further actions from your side. The costs for this deployment, at a GAS price of 70 gwei and a POL price of $0.51, would be:
GAS |
POL |
$ |
|
---|---|---|---|
Deploy |
850352 |
0.059 |
0.03 |
Save Title |
47517 |
0.0033 |
0.001 |
Save Package Data |
169549 |
0.0118 |
0.006 |
Total |
0.037 |
You spend just 4 cents to set up a decentralized, secure, and long-running service with no maintenance required.
§ Query
To query your contract data, you’ll need RPC node providers. Dozens of free providers are available at https://chainlist.org. You can choose multiple providers, and a good Web3 library can utilize a round-robin strategy at runtime to select the most efficient one for your end users. With 0xweb, the generated TypeScript or JavaScript classes not only select the best endpoints but also abstract away all blockchain communication. The clients contain high-level methods for fetching data, making the process seamless and efficient.
# The deploy command also generates the class, but manual install is also possible
npx 0xweb i 0x<address> --name AppVersionManager --chain polygon
import { AppVersionManager } from './0xc/polygon/AppVersionManager/AppVersionManager'
const manager = new AppVersionManager();
console.log(`Title`, await manager.title());
console.log(`Package`, await manager.package());
For other programming languages, there are numerous libraries available to simplify querying the blockchain. After deployment, you’ll have the contract address and ABI (interface).
Alternatively, you can launch a middleware server to query contract data using 0xweb.
npx 0xweb server start --port 3000
curl http://localhost:3000/api/c/read/AppVersionManager/package?chain=polygon
One advantage is that you don’t need to include any libraries in your application – raw HTTP requests. However, this approach relies on an additional server that you’ll need to manage. It’s often better to query the blockchain directly using 0xweb-generated classes or other blockchain libraries available.
§ Summary 🏁
This article showcased how blockchains can be both simple and powerful, offering unique advantages compared to traditional hosting solutions.
In the next article, I plan to explore decentralized BLOB storage networks such as Greenfield and Arweave, highlighting their features and benefits.
If you have any suggestions or ideas for additional features to include in the 0xweb library, feel free to share them in the comments or reach out directly at [email protected].