So one thing I always wanted to do, was to host a website, in the blockchain. Not host a website on a normal provider and have it talk to a blockchain, but actually have the website be hosted in the blockchain. At this point, I don’t see much purpose behind this approach, blockchains aren’t exactly DNS compatible right now, Ethereum does have their name service (ENS), but even then, it’s not like I can just type in the ENS name into Chrome and then have the website appear… yet.
So, let’s host a static web page in a blockchain. My blockchain of choice will be Ethereum. From here, we will go through all of the steps to accomplish being able to create, publish, and view our created website within the Ethereum blockchain. Now this is different than using a decentralized file hosting service, there are already great options for that, IPFS, or even the upcoming Swarm implementation from Ethereum will both be great for file hosting, this will end up being the approach taken to actually host web pages, what this document is proposing is a very simplistic layout for how to have smart contracts have their own little websites. Later in this research we will also look at a metatag standard and perhaps even a search engine. But to begin let’s just look at hosting a website in a smart contract.
So given that the website is going to be hosted in a smart contract, we have a few constraints, everything has to be inline or alternatively hosted in a normal CDN. So option 1 is to have things like our javascript, css, and images hosted on a CDN and then just host the HTML in the smart contract. I feel like this is cheating, so instead we are going to do everything inline.
So step 1, let’s make our little inline website. As with anything, we will just do a quick Hello World.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Ethereum Website</title>
</head>
<body>
<h2>Hello World, I'm hosted in a smart contract</h2>
</body>
</html>
That should be enough for now. Next, we need to get this wrapped in a smart contract. So let’s build our Ethereum solidity contract. This first iteration has a few obvious flaws that will will tackle one by one later in this article.
pragma solidity ^0.4.11;
contract helloWorldWeb {
function renderWeb() public pure returns (string) {
return '<!DOCTYPE html><html lang="en"><head><title>Ethereum Website</title></head><body><h2>Hello World, I\'m hosted in a smart contract</h2></body></html>';
}
}
Now we have to get this into Ethereum. For purposes of this article we will just use one of the testnets, at this point we have no reason to deploy to the main net since we aren’t actually doing anything transactional and we don’t need ENS just yet.
For this, we can just use remix, copy over your solidity code, past it, and deploy to Ropsten.
creation of helloWorldWeb pending...
[block:2701231 txIndex:9] from:0x1e3...275c7, to:helloWorldWeb.(constructor), value:0 wei, 0 logs, data:0x606...60029, hash:0x778...002d4
From the transaction ID we grab our smart contract address, this is our URL for the time being. So let’s quickly check that everything worked out fine. We will use web3.js
*Below where it says /* ENTER YOU PROVIDER HERE */ you can either connect to a local node you are running, connect to a node you know about, or if you just want to use a third party Ethereum Service Provider (ESP), then head over to infura, sign up for free, and get a provider link.*
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider(/* ENTER YOUR PROVIDER HERE */));
const abi = [{"constant":true,"inputs":[],"name":"renderWeb","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"}];
const contract = new web3.eth.Contract(abi, '0x32636e8Ef088f8F09e3eEEef87362AEe54Ed46cA');
contract.methods.renderWeb().call({from: '0x32636e8Ef088f8F09e3eEEef87362AEe54Ed46cA'}, function(error, result){
console.log('0x4:'+result)
});
And we get
0x4:<!DOCTYPE html><html lang="en"><head><title>Ethereum Website</title></head><body><h2>Hello World, I'm hosted in a smart contract</h2></body></html>
Great, there is our HTML.
Now we need to render it, here we have a few options. Hosted solution (defeats the purpose of all of this), local solution (kind of nice but high barrier to entry), chrome extension (lot’s of constraints, but pretty cool)
So let’s look at the local option first.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Ethereum Web Explorer</title>
<script src="/* LINK TO web3.min.js */"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
web3 = new Web3(new Web3.providers.HttpProvider(/* YOUR ESP HERE */));
document.getElementById("myButton").addEventListener("click", printAccountBalance);
function printAccountBalance() {
const abi = [{"constant":true,"inputs":[],"name":"renderWeb","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"}];
const contract = web3.eth.contract(abi).at(/* YOUR CONTRACT HERE */);
const html = contract.renderWeb()
document.getElementById("display").innerHTML = html
}
});
</script>
</head>
<body style="width:500px;height:500px;">
<h2>Ethereum Web Explorer</h2>
<div id="display">Dummy Text</div>
<button id="myButton">Load Page</button>
</body>
</html>
Pretty straight forward, we load up web3.min.js from Ethereum. We attach a listener to myButton to load the page we want, web3 grabs the contract and calls renderWeb and we display; here is the result;
So now, technically, we already have a completely decentralized and free website hosted for us on Ethereum.
From here let’s expand to turn this into more of a browser experience; So first off, we want to be able to explore any contract, and actually browse the different ones. So let’s add the “URL” (smart contract address) as a parameter;
<!DOCTYPE html>
<html lang="en">
<head>
<title>Ethereum Web Explorer</title>
<script src="/* web3.min.js */"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
web3 = new Web3(new Web3.providers.HttpProvider(/ * ESP */));
document.getElementById("myButton").addEventListener("click", printAccountBalance);
function printAccountBalance() {
var contractAddress = document.getElementById("url").value;
const abi = [{"constant":true,"inputs":[],"name":"renderWeb","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"}];
const contract = web3.eth.contract(abi).at(contractAddress);
const html = contract.renderWeb()
document.getElementById("display").innerHTML = html
}
});
</script>
</head>
<body style="width:500px;height:500px;">
<h2>Ethereum Web Explorer</h2>
<input id="url" type=text size=50 name=url>
<div id="display">Dummy Text</div>
<button id="myButton">Load Page</button>
</body>
</html>
Easy enough, so now we already have the browser approach, we set the “URL”, and we can view the contract. So let’s create another contract and test it.
Again, contract.sol -> remix -> ropsten -> deploy. Now let’s view contract #1
And now let’s view contract #2;
So now, essentially we have a web explorer! This is easy to keep as a local file, deploy online on a simple portal, or build into a chrome extension.
But now let’s look at our solidity contract. I’ts immutable. And that’s a bit of an issue. So what happens when we want to update our HTML? Do we really want to deploy a new smart contract every single time? Definitely not. So let’s see about modifying it, so that it instead allows us to update our HTML.
At it’s most basic we simply want to change that the HTML returned is saved in the state, and that we can update the state whenever we want. Again very straight forward;
pragma solidity ^0.4.11;
contract helloWorldWeb {
address public owner;
string html;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function helloWorldWeb() public {
owner = msg.sender;
}
function setHTML(string _html) payable public onlyOwner {
html = _html;
}
function renderWeb() public view returns (string) {
return html;
}
}
Now if we look at our new contract;
The next step is having contracts create their own meta tags as well, this will allow contracts to be indexed based on their tags and purpose, if we can accomplish this, we can have a fully decentralized smart contract search engine for smart contract websites.
More details to follow in my next articles.
✅ @andrecronje, I gave you an upvote on your first post! Please give me a follow and I will give you a follow in return!
Please also take a moment to read this post regarding bad behavior on Steemit.
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit