How To Create A Censorship Resistant Domain Name System On Ethereum Classic

February 28, 2017 by Christian Seberino

Introduction

Internet

The Domain Name System (DNS) maps domains to Internet Protocol (IP) addresses. Governments, corporations and other entities have attempted to censor this system for various reasons. Therefore, it is desirable to create a censorship resistant alternative. Furthermore, DNS like systems are useful for other purposes such as cryptocurrencies, inventory tracking and voting.

The Ethereum Classic (ETC) system automatically provides censorship resistance! It is only necessary to write a smart contract to store and retrieve information on the blockchain.

Code

Here is Serpent code that implements a DNS type system on the ETC platform:

#
# Implements a domain name system.
#
# The data keyword declares global objects for the smart contract storage space.
#
# The msg global object contains information about the calling account such as
# the ETC address and the amount of aETC (10^(-18) ETC) it sent to the smart
# contract.
#

SET_UP_FEE = 1

data storage[](address, owner)

def set(domain, address, owner):
        #
        # Sets up the information for a domain and returns a status message.
        # Can be used to set up new domains as well as modify the information of
        # existing domains.  The address argument should be an IP address and
        # the owner argument should be an ETC address.  Setting up new domains
        # requires a set up fee to discourage cybersquatting and other attacks.
        # There is no charge for modifying existing records.  The address of a
        # domain cannot be blank.
        #

        if   self.storage[domain].address:
                if self.storage[domain].owner == msg.sender:
                        self.storage[domain].address = address
                        self.storage[domain].owner   = owner
                        status = "Success: Changed."
                else:
                        status = "Error: Cannot change."
        elif ((msg.value >= SET_UP_FEE) and address):
                self.storage[domain].address = address
                self.storage[domain].owner   = owner
                status = "Success: Set up."
        else:
                status = "Error: Cannot set up."

        return status

def get(domain):
        #
        # Returns the information for a domain including a status message.
        #

        if self.storage[domain].address:
                address = self.storage[domain].address
                owner   = self.storage[domain].owner
                status  = "Success: Retrieved."
        else:
                address = ""
                owner   = ""
                status  = "Error: Cannot retrieve."

        return ([status, address, owner], items = 3)

This smart contract has methods to create, modify and retrieve domain records. All methods supply status messages. Notice it is necessary to send a small payment to set up new domain records. This discourages cybersquatting and other attacks.

Testing & Deployment

Testing Script

For testing I will use the following serpent_test script:

#!/usr/bin/env python

"""
Tests Serpent functions.

Serpent files     correspond to Ethereum Classic smart contracts.
Serpent functions correspond to Ethereum Classic smart contract   methods.

Serpent function invocation arguments must all be hexadecimal.

Testing is done on a mock blockchain.

1 aETC = 10^(-18) ETC

Usage: serpent_test <file> <function invocation> <aETC sending>
"""

import ethereum.tester
import ethereum.abi
import serpent
import binascii
import re
import sys

PRIVATE_KEY = ethereum.tester.k0
HEXADECIMAL = 16

program      = open(sys.argv[1]).read()
machine_code = serpent.compile(program)
blockchain   = ethereum.tester.state()
address      = blockchain.evm(machine_code)
method       = sys.argv[2][:sys.argv[2].find("(")]
args         = sys.argv[2][sys.argv[2].find("(") + 1:-1]
args         = [int(e, HEXADECIMAL) for e in args.split(",") if e]
call_data    = serpent.mk_full_signature(program)
call_data    = [e for e in call_data if e["name"].startswith(method + "(")]
call_data    = ethereum.abi.ContractTranslator(call_data).encode(method, args)
aetc_sending = int(sys.argv[3])
result       = blockchain.send(PRIVATE_KEY, address, aetc_sending, call_data)
print "call data : 0x" + binascii.hexlify(call_data)
print "result    : 0x" + binascii.hexlify(result)

Deployment Script

For deployment, I will use the following node_cmd script with an ETC Parity node:

#!/usr/bin/env python3

"""
Sends commands and receives output from Ethereum Classic Parity nodes.

Ethereum Classic Parity nodes listen for POST requests.

Usage: node_cmd <command> [<argument>]...
"""

import urllib.request
import json
import sys

NODE_URL = "http://127.0.0.1:8545"

try:
        args = [json.loads(sys.argv[2].replace("'", '"'))] + sys.argv[3:]
except:
        args = sys.argv[2:]
node_data = {"method"  : sys.argv[1],
             "params"  : args,
             "jsonrpc" : "2.0",
             "id"      : 1}
node_data = json.dumps(node_data).encode()
node_post = urllib.request.Request(NODE_URL)
node_post.add_header("Content-Type", "application/json")
node_post = urllib.request.urlopen(node_post, node_data).read().decode()
try:
        print(json.loads(node_post)["result"])
except:
        print(json.loads(node_post))

Pretty Printing Script

For pretty printing lists, from hexadecimal encodings, I will use the following serpent_list script:

#!/usr/bin/env python3
#
# Extracts and pretty prints lists from hexadecimal encodings.
#
# Usage: serpent_list <list>

import binascii
import textwrap
import sys

HEADER_LEN  = 64
ELEMENT_LEN = 32

elements = sys.argv[1][len("0x") + 2 * HEADER_LEN:]
for i, e in enumerate(textwrap.wrap(elements, 2 * ELEMENT_LEN)):
        print("Element #{}".format(i))
        print("\t0x" + e)
        print("\t"   + str(binascii.unhexlify(e))[1:])

Example

Here is a slightly edited actual session on a Linux computer running an ETC Parity node. The domain name system code is in a file called dns.se:

% ETC_ADDRESS="0x853323f554263bb62af7080ef321f115ec623637"

% echo $ETC_ADDRESS
0x853323f554263bb62af7080ef321f115ec623637

% node_cmd eth_getBalance $ETC_ADDRESS latest
0xde2b995bce40ffe

% PASSWORD="mysecretpassword"

% echo $PASSWORD
mysecretpassword

% MACHINE_CODE="0x"`serpent compile dns.se`

% echo $MACHINE_CODE
0x6103338061000e60003961034156600061025f537c01000000000000000000000000000000000000000000000000000000006000350460016020526304f66c8781141561020a5760043560605260243560805260443560a05260606060599059016000905260008152606051816020015260008160400152809050205415610141573360606060599059016000905260008152606051816020015260018160400152809050205414156101165760805160606060599059016000905260008152606051816020015260008160400152809050205560a0516060606059905901600090526000815260605181602001526001816040015280905020557f537563636573733a204368616e6765642e0000000000000000000000000000006101405261013c565b7f4572726f723a2043616e6e6f74206368616e67652e0000000000000000000000610140525b6101fb565b6020513412151561015457608051610157565b60005b156101d45760805160606060599059016000905260008152606051816020015260008160400152809050205560a0516060606059905901600090526000815260605181602001526001816040015280905020557f537563636573733a205365742075702e00000000000000000000000000000000610140526101fa565b7f4572726f723a2043616e6e6f74207365742075702e0000000000000000000000610140525b5b610140516101a05260206101a0f35b63846719e081141561033157600435606052606060605990590160009052600081526060518160200152600081604001528090502054156102bd5760606060599059016000905260008152606051816020015260008160400152809050205460805260606060599059016000905260008152606051816020015260018160400152809050205460a0527f537563636573733a205265747269657665642e00000000000000000000000000610140526102ed565b6000608052600060a0527f4572726f723a2043616e6e6f742072657472696576652e000000000000000000610140525b6080599059016000905260038152610140516020820152608051604082015260a0516060820152602081019050602060408203526003602082035260a060408203f3505b505b6000f3

% TRANS_HASH=`node_cmd personal_signAndSendTransaction "{'from' : '$ETC_ADDRESS', 'data' : '$MACHINE_CODE'}" $PASSWORD`

% echo $TRANS_HASH
0xe9dfcf382d6f713a662abd000df1a410bda0774d2c927cd7502be51cb3b77c85

% node_cmd eth_getTransactionByHash $TRANS_HASH
{'gasPrice': '0x4a817c800', 'transactionIndex': '0x1', 'r': '0x140838401aeb859aa61503110178c9c1a5f31f776a1318b1293ef996277e76d7', 'from': '0x853323f554263bb62af7080ef321f115ec623637', 'blockNumber': '0x3107d5', 'raw': '0xf903990b8504a817c800830e57e08080b903456103338061000e60003961034156600061025f537c01000000000000000000000000000000000000000000000000000000006000350460016020526304f66c8781141561020a5760043560605260243560805260443560a05260606060599059016000905260008152606051816020015260008160400152809050205415610141573360606060599059016000905260008152606051816020015260018160400152809050205414156101165760805160606060599059016000905260008152606051816020015260008160400152809050205560a0516060606059905901600090526000815260605181602001526001816040015280905020557f537563636573733a204368616e6765642e0000000000000000000000000000006101405261013c565b7f4572726f723a2043616e6e6f74206368616e67652e0000000000000000000000610140525b6101fb565b6020513412151561015457608051610157565b60005b156101d45760805160606060599059016000905260008152606051816020015260008160400152809050205560a0516060606059905901600090526000815260605181602001526001816040015280905020557f537563636573733a205365742075702e00000000000000000000000000000000610140526101fa565b7f4572726f723a2043616e6e6f74207365742075702e0000000000000000000000610140525b5b610140516101a05260206101a0f35b63846719e081141561033157600435606052606060605990590160009052600081526060518160200152600081604001528090502054156102bd5760606060599059016000905260008152606051816020015260008160400152809050205460805260606060599059016000905260008152606051816020015260018160400152809050205460a0527f537563636573733a205265747269657665642e00000000000000000000000000610140526102ed565b6000608052600060a0527f4572726f723a2043616e6e6f742072657472696576652e000000000000000000610140525b6080599059016000905260038152610140516020820152608051604082015260a0516060820152602081019050602060408203526003602082035260a060408203f3505b505b6000f3819da0140838401aeb859aa61503110178c9c1a5f31f776a1318b1293ef996277e76d7a05181901f83bbf82d5c1c31ef499f6303b44ebfb5a6099a389d55e1047627acb3', 'publicKey': '0xb1be15931dd263cda0c6be5aed9e475c93a2b1a1aac1c9b6a661c1be6f628536d0e07de4f60be6736896584beb7927247e06cd9fa3d2f79faff7fe145c9726c1', 'creates': '0xa00ad648305be098d97612d413e8368c3a048c72', 'to': None, 'value': '0x0', 's': '0x5181901f83bbf82d5c1c31ef499f6303b44ebfb5a6099a389d55e1047627acb3', 'nonce': '0xb', 'networkId': 61, 'hash': '0xe9dfcf382d6f713a662abd000df1a410bda0774d2c927cd7502be51cb3b77c85', 'input': '0x6103338061000e60003961034156600061025f537c01000000000000000000000000000000000000000000000000000000006000350460016020526304f66c8781141561020a5760043560605260243560805260443560a05260606060599059016000905260008152606051816020015260008160400152809050205415610141573360606060599059016000905260008152606051816020015260018160400152809050205414156101165760805160606060599059016000905260008152606051816020015260008160400152809050205560a0516060606059905901600090526000815260605181602001526001816040015280905020557f537563636573733a204368616e6765642e0000000000000000000000000000006101405261013c565b7f4572726f723a2043616e6e6f74206368616e67652e0000000000000000000000610140525b6101fb565b6020513412151561015457608051610157565b60005b156101d45760805160606060599059016000905260008152606051816020015260008160400152809050205560a0516060606059905901600090526000815260605181602001526001816040015280905020557f537563636573733a205365742075702e00000000000000000000000000000000610140526101fa565b7f4572726f723a2043616e6e6f74207365742075702e0000000000000000000000610140525b5b610140516101a05260206101a0f35b63846719e081141561033157600435606052606060605990590160009052600081526060518160200152600081604001528090502054156102bd5760606060599059016000905260008152606051816020015260008160400152809050205460805260606060599059016000905260008152606051816020015260018160400152809050205460a0527f537563636573733a205265747269657665642e00000000000000000000000000610140526102ed565b6000608052600060a0527f4572726f723a2043616e6e6f742072657472696576652e000000000000000000610140525b6080599059016000905260038152610140516020820152608051604082015260a0516060820152602081019050602060408203526003602082035260a060408203f3505b505b6000f3', 'v': '0x9d', 'gas': '0xe57e0', 'standardV': '0x0', 'blockHash': '0x96a680068fe23c202a7d7ecd01665237de7358de2cb6644585b326f2ead1fec7'}

% SMART_CONTRACT=0xa00ad648305be098d97612d413e8368c3a048c72

% echo $SMART_CONTRACT
0xa00ad648305be098d97612d413e8368c3a048c72

% DOMAIN=`python3 -c "import binascii ; print(binascii.hexlify(b'mydomain.com'))"`
% DOMAIN=0x${DOMAIN:2:-1}

% echo $DOMAIN
0x6d79646f6d61696e2e636f6d

% IP_ADDRESS=`python3 -c "import binascii ; print(binascii.hexlify(b'192.168.1.100'))"`
% IP_ADDRESS=0x${IP_ADDRESS:2:-1}

% echo $IP_ADDRESS
0x3139322e3136382e312e313030

% serpent_test dns.se "set($DOMAIN, $IP_ADDRESS, $ETC_ADDRESS)" 1
call data : 0x04f66c8700000000000000000000000000000000000000006d79646f6d61696e2e636f6d000000000000000000000000000000000000003139322e3136382e312e313030000000000000000000000000853323f554263bb62af7080ef321f115ec623637
result    : 0x537563636573733a205365742075702e00000000000000000000000000000000

% CALL_DATA=0x04f66c8700000000000000000000000000000000000000006d79646f6d61696e2e636f6d000000000000000000000000000000000000003139322e3136382e312e313030000000000000000000000000853323f554263bb62af7080ef321f115ec623637

% echo $CALL_DATA
0x04f66c8700000000000000000000000000000000000000006d79646f6d61696e2e636f6d000000000000000000000000000000000000003139322e3136382e312e313030000000000000000000000000853323f554263bb62af7080ef321f115ec623637

% node_cmd personal_signAndSendTransaction "{'from' : '$ETC_ADDRESS', 'to' : '$SMART_CONTRACT', 'value' : '0x1', 'data' : '$CALL_DATA'}" $PASSWORD
0xbd30e457932d7f34862652511f292dc8f005d85acde415e1408c356fbacda8e8

% serpent_test dns.se "get($DOMAIN)" 0
call data : 0x846719e000000000000000000000000000000000000000006d79646f6d61696e2e636f6d
result    : 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034572726f723a2043616e6e6f742072657472696576652e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

% CALL_DATA=0x846719e000000000000000000000000000000000000000006d79646f6d61696e2e636f6d

% echo $CALL_DATA
0x846719e000000000000000000000000000000000000000006d79646f6d61696e2e636f6d

% RESULT=`node_cmd eth_call "{'to' : '$SMART_CONTRACT', 'data' : '$CALL_DATA'}"`

% echo $RESULT
0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003537563636573733a205265747269657665642e00000000000000000000000000000000000000000000000000000000000000003139322e3136382e312e313030000000000000000000000000853323f554263bb62af7080ef321f115ec623637

% serpent_list $RESULT
Element #0
	0x537563636573733a205265747269657665642e00000000000000000000000000
	'Success: Retrieved.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Element #1
	0x000000000000000000000000000000000000003139322e3136382e312e313030
	'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00192.168.1.100'
Element #2
	0x000000000000000000000000853323f554263bb62af7080ef321f115ec623637
	'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x853#\xf5T&;\xb6*\xf7\x08\x0e\xf3!\xf1\x15\xecb67'

% python3 -c "print($ETC_ADDRESS == `echo \`serpent_list $RESULT\` | cut -c 238-303`)"
True

Conclusion

light bulb

A censorship resistant DNS replacement is just one of many potentially useful ETC applications. Hopefully this example will encourage you to come up with your own ideas.

Feedback

You can contact me by clicking any of these icons:

twitter facebook linkedin

Acknowledgements

I would like to thank IOHK (Input Output Hong Kong) for funding this effort.

License

license

This work is licensed under the Creative Commons Attribution ShareAlike 4.0 International License.

Archive Previous posts

June 17, 2017Christian Seberino

When Absolutely No One Can Steal Or Return Lost Ethereum Classic Funds

June 17, 2017Christian Seberino

Should The Ethereum Classic Community Be Ashamed Of Promoting Privacy?

June 17, 2017Christian Seberino

ICOs & Custom Cryptocurrencies On Ethereum Classic

May 19, 2017Prophet Daniel

Stand up from the crowd

May 11, 2017Carlo V

ETC Weekly Newsletter: Dev Update 10!

May 1, 2017Christian Seberino

Why You Should LOVE Proof Of Stake Systems — Hybrids!

April 28, 2017Christian Seberino

Ethereum Classic World Computer Transactions Explained

April 28, 2017Christian Seberino

Ethereum Classic Blocks Explained: The Three Categories

April 19, 2017Carlo V

ETC Weekly Newsletter: New all time highs as ETC surges!

April 18, 2017Christian Seberino

Ethereum Classic Public And Private Keys: A Little Enlightenment

April 13, 2017Carlo V

ETC Weekly Newsletter: New devs on ETCdev Team.

March 30, 2017Christian Seberino

The Ethereum Classic World Computer Accounts & States Explained

March 29, 2017Carlo V

ETC Weekly Newsletter: Dev Update + News from Bitkio.

March 24, 2017Christian Seberino

How To Improve Ethereum Classic Immutability Discussions

March 16, 2017Carlo V

ETC Weekly Newsletter: Dev update and more

March 13, 2017Christian Seberino

Ethereum's Vitalik Buterin Discusses The New Viper Smart Contract Programming Language

March 8, 2017Carlo V

ETC Weekly Newsletter: Dev Updates + New Discussions

March 2, 2017Carlo V

ETC Weekly Newsletter : Monetary Policy Statement.

February 28, 2017Christian Seberino

An Interview With The Anonymous Individual That Started Ethereum Classic

February 28, 2017Christian Seberino

How To Create A Censorship Resistant Domain Name System On Ethereum Classic

February 20, 2017Carlo V

ETC Weekly Newsletter : Treasury Proposal

February 13, 2017Christian Seberino

Should We Make ⟠ The Ethereum Classic Currency Symbol?

February 10, 2017Christian Seberino

Serpent: Introduction To The BEST Ethereum Classic Smart Contract Language

February 10, 2017Christian Seberino

Proposal: Ethereum Classic Currency And Logo Conventions To Improve Communication And Avoid Expensive Mistakes

February 10, 2017Christian Seberino

Why Ethereum Classic Uses An Incorrect SHA3 Implementation

February 10, 2017Christian Seberino

Hashes: An Introduction & Why They Are Foundational To The Internet & Blockchains

February 10, 2017Christian Seberino

Why Bloom Filters Are So Cool (+ Useful!) For Blockchains & Beyond: An Introduction

February 1, 2017Carlo V

ETC Weekly Newsletter : Another Great Month Ahead

January 24, 2017Prophet Daniel

Ethereum Classic Harmony

January 17, 2017Carlo V

ETC Weekly Newsletter : Protocol Update Successful!

January 6, 2017Prophet Daniel

Sustainable Development Goals

January 4, 2017Carlo V

ETC Weekly Newsletter : Happy New Year!

December 29, 2016Carlo V

ETC Weekly Newsletter : End Of 2016!

December 28, 2016Christian Seberino

Zero Knowledge Proofs For Dummies

December 20, 2016Carlo V

ETC Weekly Newsletter : In Case You Missed It

December 16, 2016Christian Seberino

How To EASILY Set Up An AMAZING Ethereum Classic Node & Talk To It With Your OWN Code

December 14, 2016Carlo V

ETC Weekly Newsletter : ETC Meetup in London + The New Team

December 12, 2016Carlo V

Introducing The Grothendieck Team

December 6, 2016Christian Seberino

Why Would I Choose To Run My Application On Ethereum / Classic Instead Of The World Wide Web?

December 6, 2016Carlo V

ETC Weekly Newsletter : The Grothendieck Team

December 4, 2016Arvicco

ETC End of Year and Monetary Policy Event: London, December 13th

December 1, 2016Christian Seberino

Why InterPlanetary File System & Its Ilk Are A Big Deal For Blockchains & Beyond

November 29, 2016Carlo V

ETC Weekly Newsletter : Network Update

November 23, 2016Christian Seberino

The Skinny On Smart Contracts: An Introduction & Why You Should Care

November 22, 2016Carlo V

ETC Weekly Newsletter : Monetary Policy Update

November 15, 2016Christian Seberino

The Bare Basics Of Money And Monetary Policy WITH A FEW WORDS FROM SATOSHI NAKAMOTO

November 15, 2016Carlo Vicari

ETC Newsletter

November 8, 2016Carlo Vicari

ETC Newsletter : 2016-11-01 - 2016-11-08

November 4, 2016Christian Seberino

Let's Admit Blockchains Are Weird: An Introduction To The Strangeness

November 1, 2016Carlo Vicari

ETC Newsletter : 2016-10-24 - 2016-11-01

October 31, 2016Carlos Graterol

Instead of The Halvening, A Tithing for ETC

October 17, 2016Arvicco

Gas Reprice Hard Fork on ETC block 2500000 (October 25)

October 14, 2016Christian Seberino

Why Another Hard Fork To Deal With The Recent Denial Of Service Attack Spam Shouldn't Be Controversial

October 13, 2016Christian Seberino

Ethereum / Classic Denial Of Service Attacks & The Estonian Cyberwar

October 12, 2016Christian Seberino

Cuban Piracy & Why Merkle Trees Are So Awesome For Blockchains

October 11, 2016Christian Seberino

Navajo Indians Help Explain Ethereum / Classic Replay Attacks

September 18, 2016ProphetDaniel

The Invisible Field

September 9, 2016Arvicco

Code is Law and the Quest for Justice

September 1, 2016Ethereum Classic

CHBTC contributes funds to foster growth of Ethereum Classic

August 18, 2016Arvicco

Ethereum Classic Kickoff (London)

August 16, 2016ProphetDaniel

Nature Inspired Ethereum Classic Community Dynamics Proposal

August 14, 2016DaxClassix

New Website Created

August 11, 2016ProphetDaniel

Decentralized anarchist governance system

August 10, 2016ProphetDaniel

Couple Values That Forked Ethereum Broke

July 27, 2016Arvicco

Getting things done in a decentralized way

July 25, 2016Arvicco

What can I do to help Ethereum Classic project?

July 24, 2016Arvicco

ETC exchange trading and other news

July 22, 2016Arvicco

ETC - new Ethereum Classic ticker symbol

July 15, 2016Arvicco

Let's keep the original censorship-resistant Ethereum going!

July 11, 2016Arvicco

A Crypto-Decentralist Manifesto