Set Up a Local EOS Testnet – FullStacked
Bitcoin, the first decentralized digital currency, saw its first transfer from one account to another January 2009. But it wasn’t until a year later when a public market allowing the trading of Bitcoin emerged. The first cryptocurrency exchange wasn’t Bitstamp or Mt. Gox, but Bitcoinmarket.com, a now dead platform. What an exchange did was bring consensus on what Bitcoin was worth as a currency. But with the rise of Bitcoinmarket followed an influx of scammers. Paypal, which allowed the trading of bitcoin with fiat, was removed from the site.
Bitcoinmarket’s market successor, Mt. Gox, began handling 70% of all bitcoin volume by January 2014. One month later Mt. Gox became bankrupt due to a hack. Mt. Gox had previously seen a large hack in 2011, however, still became the largest exchange before their hack in 2014.
Bitcoin, around the ages of Bitcoinmarket, started trading at ~$0.003 per Bitcoin. Before 2014, that number wavered around $100 per Bitcoin. Right before the Mt. Gox 2014 hack, Bitcoin’s price reached over $1,000, a 10x in a few months. Bitcoin, at the time of this writing in Summer 2019, trades over $10,000.
Cryptocurrency created a digital FOREX trading market online. Whereby normal FOREX deals with trading centralized currencies backed by the economies of countries, cryptocurrency trading typically has no government affiliation, and are run by incentivized volunteers, making these currencies decentralized currencies. Think Uber but finance.
The true evolution of these decentralized currencies came with smart contract enabled platforms, the first of which is known as Ethereum. Ethereum sprung into the public summer 2015, lead by Vitalik Buterin, co-founder of Bitcoin Magazine. Ethereum enabled the addition of code handling the transfer of funds, enabling applications interacting and storing data to the blockchain.
With the introduction of smart contracts, entire backends could now be hosted on the blockchain instead of servers. Each volunteer running the Ethereum blockchain would collectively become one computer, creating one super-server without a single point of failure.
Even more-so, with the introduction of Ethereum, entirely new decentralized currencies could be launched using Ethereum as a base.
Like in traditional startups and the stock market, cryptocurrency projects also seek out venture capitalist (VC)funding. This funding comes in seed rounds, as well as VC rounds before launching into exchanges. This VC funding method was previously known as the Initial Coin Offering (ICO). One of these ICOs, however, led to the forking of the Ethereum cryptocurrency.
An ICO called the DAO, short for Decentralized Autonomous Organization, had raised $150 million in ICO funding. Before funding had finished, $50 million worth of ETH were stolen.
The attacker managed to combine two exploits: (1) calling the split DAO function recursively and (2) splitting without destroying the tokens in the original DAO. […] The combination of both exploits multiplied the effect.
— Summary from Consensys
These $50 million wouldn’t have been stolen were it for stricter testing and smart contract auditing. This situation highlights the most important aspect of smart contract development: testing.
EOS is a much faster smart contract platform than Ethereum. While Ethereum offers 15 transactions per seconds, EOS transactions per second reaches the thousands. Seeing as each smart contract function call acts as a transaction, this difference is night and day for the end user. However, as a smart contract platform, EOS also requires auditing of smart contracts.
The benefit of running your own EOS testnet is that you can deploy EOS smart contracts for free for testing. You can generate as many tokens as you’d like for testing, as well as generate as many accounts as you’d like, and transfer tokens between those accounts.
Generating tokens and freely trading them is helpful when making your decentralized application dealing with money, ensuring your application is secure.
The EOS stack has 3 parts:
- The Command Line Interface (CLEOS)
- The instance or node (NODEOS)
- And the key and wallet manager (KEOSD)
For most of this tutorial, we’ll be using cleos to configure the testing environment, but nodeos and keosd will be used to initiate the environment.
This guide will be broken down to these sections:
To begin the process, we first have to install EOS binaries. If you are on Mac, we can use Homebrew.
brew tap eosio/eosiobrew install eosio
Currently, EOS doesn’t have developer tools for native Windows operating systems. If using Windows, you can either download a Virtual Machine and run a Linux operating system such as Ubuntu, or download the Ubuntu terminal in the Microsoft Store.
If using Ubuntu:
wget https://github.com/EOSIO/eos/releases/download/v1.7.0/eosio_1.7.0-1-ubuntu-16.04_amd64.deb
sudo apt install ./eosio_1.7.0-1-ubuntu-16.04_amd64.deb
If you recently installed Ubuntu via the Microsoft Store on Windows, right click allows you to paste.
Once installed, we can initiate keosd right away.
keosd &
If the eosio binaries were installed, you should see something like the following output:
info 2018-11-26T06:54:24.789 thread-0 wallet_plugin.cpp:42 plugin_initialize ] initializing wallet plugininfo 2018-11-26T06:54:24.795 thread-0 http_plugin.cpp:554 add_handler ] add api url: /v1/keosd/stopinfo 2018-11-26T06:54:24.796 thread-0 wallet_api_plugin.cpp:73 plugin_startup ] starting wallet_api_plugininfo 2018-11-26T06:54:24.796 thread-0 http_plugin.cpp:554 add_handler ] add api url: /v1/wallet/createinfo 2018-11-26T06:54:24.796 thread-0 http_plugin.cpp:554 add_handler ] add api url: /v1/wallet/create_keyinfo 2018-11-26T06:54:24.796 thread-0 http_plugin.cpp:554 add_handler ] add api url: /v1/wallet/get_public_keys
In a new tab in your terminal, we can also initiate a nodeos instance.
For a local testnet, initialize using these settings.
nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::chain_api_plugin --plugin eosio::http_plugin --plugin eosio::history_plugin --plugin eosio::history_api_plugin --access-control-allow-origin='*' --contracts-console --http-validate-host=false --verbose-http-errors --filter-on='*' >> nodeos.log 2>&1 &
And there we go. Your local testnet should be running. But…
Is Everything Working Correctly?
We can check if nodeos is producing blocks.
tail -f nodeos.log
You should see a log. If everything is working correctly, you should see something like the following.
1929001ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000366974ce4e2a... #13929 @ 2018-05-23T16:32:09.000 signed by eosio [trxs: 0, lib: 13928, confirmed: 0]1929502ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000366aea085023... #13930 @ 2018-05-23T16:32:09.500 signed by eosio [trxs: 0, lib: 13929, confirmed: 0]1930002ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000366b7f074fdd... #13931 @ 2018-05-23T16:32:10.000 signed by eosio [trxs: 0, lib: 13930, confirmed: 0]1930501ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000366cd8222adb... #13932 @ 2018-05-23T16:32:10.500 signed by eosio [trxs: 0, lib: 13931, confirmed: 0]1931002ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000366d5c1ec38d... #13933 @ 2018-05-23T16:32:11.000 signed by eosio [trxs: 0, lib: 13932, confirmed: 0]1931501ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000366e45c1f235... #13934 @ 2018-05-23T16:32:11.500 signed by eosio [trxs: 0, lib: 13933, confirmed: 0]1932001ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000366f98adb324... #13935 @ 2018-05-23T16:32:12.000 signed by eosio [trxs: 0, lib: 13934, confirmed: 0]1932501ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 00003670a0f01daa... #13936 @ 2018-05-23T16:32:12.500 signed by eosio [trxs: 0, lib: 13935, confirmed: 0]1933001ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 00003671e8b36e1e... #13937 @ 2018-05-23T16:32:13.000 signed by eosio [trxs: 0, lib: 13936, confirmed: 0]1933501ms thread-0 producer_plugin.cpp:585 block_production_loo ] Produced block 0000367257fe1623... #13938 @ 2018-05-23T16:32:13.500 signed by eosio [trxs: 0, lib: 13937, confirmed: 0]
This nodeos instance is your local EOS testnet. If it isn’t running, you’ll see so here. Errors with nodeos occur if you close a terminal or turn off your device without cleaning exiting nodeos and keosd. To terminate nodeos and keosd cleanly, and prevent these issues, press Ctrl + C in their windows, or use pkill nodeos and pkill koesd, once you choose to terminate your local testnet.
Press Ctrl + C to close the nodeos log.
Next we check our wallets with cleos.
cleos wallet list
If this is your first time dealing with eosio, you should see an empty list.
Wallets:[]
Finally, we check our nodeos endpoint. We have two options:
- Visit http://localhost:8888/v1/chain/get_info in your browser
- Print out http://localhost:8888/v1/chain/get_info in the terminal
curl http://localhost:8888/v1/chain/get_info
This address, the nodeos endpoint, is needed for connecting any app you make and any EOS wallet provider, such as Scatter Wallet, with your EOS testnet. Since we have that, this means we can now…
To add your nodeos instance to Scatter, you first need to have Scatter installed. You can download Scatter for your respective operating system on their website.
Once you have Scatter installed and ready with the password you created for your account, you can begin to add your nodeos instance to the wallet, so Scatter can interface a frontend you design with your local EOS testnet.
From the home screen, enter settings.
In settings, you’ll see a list of options included a set of options outlined in red saying danger. Those are the options we want to look at. Within the “Danger Zone” select Networks.
Networks will allow you to add different EOS nodeos instances. It’s required to add any local testnet, as Scatter defaults the the mainnet.
Once there, we enter the required information. All the info you need is found inside of the http://localhost:8888/v1/chain/get_info json text. There, the most important piece is the Chain ID. Everything else, including the ports, is also found there. If your nodeos instance is running, you’ll have access to that json text.
Name your network settings. I named mine localhost, since I am running it locally on my computer.
What this allows you to do is add accounts that are made within this testnet into Scatter wallet.
We don’t have any accounts, so we’ll need to create some.
To ready our testnet with EOS accounts, we need to install the EOSIO Contract Development Toolkit (CDT). The EOS CDT is a collection of tools used in compiling smart contracts.
If you’re on MacOS, you can use Homebrew.
brew tap eosio/eosio.cdt
brew install eosio.cdt
If using Ubuntu:
wget https://github.com/EOSIO/eosio.cdt/releases/download/v1.6.1/eosio.cdt_1.6.1-1_amd64.deb
sudo apt install ./eosio.cdt_1.6.1-1_amd64.deb
Now that we have all the required tools, let’s make a development wallet. An EOS wallet contains the private key you need to sign transactions on the EOS blockchain. Recently, EOS wallets have served more as Authenticators, allowing you to log into a dApp in addition to interacting with the EOS blockchain on your behalf. We will be making a development wallet to publish local smart contracts and create accounts for your testnet.
When we create the development wallet, a password will be returned. We specify whether this password returns to the console or is saved in a file.
cleos wallet create --to-console
cleos wallet create --to-file <path/filename.txt>
Whichever way you requested the password, save it, as you’ll need it.
Now that the wallet is created, all wallets are closed by default, so to use it, we have to open it.
cleos wallet open
You can also see a list of wallets with the following:
cleos wallet list
Opening a wallet does not unlock it. Once opened, you must still unlock the wallet to use it.
cleos wallet unlock
When attempting to unlock, you will be prompted to
Expected output:
Wallets: [ “default *” ]
An asterisk (*) next to a wallet indicates the wallet is unlocked.
With a wallet, you need to create a private-public key pairing. You can do so with cleos.
cleos wallet create_key
Now, every EOS chain, in every EOS network, needs an eosio account to sign transactions limited to only the eosio account. For testnet use, EOS provides a development key for importing a development eosio account. This key is the same everywhere for development.
# eosio development key
5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
We’ll need to import the eosio development account.
cleos wallet import
# then enter the eosio development key
Never use the development key for any production account! Doing so will result in the loss of access to your account, as this private key is publicly known.
Now that all the requirements are in place, we can set up test accounts for us to use in our testnet.
In EOS, accounts aren’t just associated with a public key, they are associated with a username that is linked to a private/public key pairing. This username is required for sending transaction and interacting with EOS smart contracts.
EOS accounts are flexible, in so that they can be owned and controlled by an individual, or by a set of individuals who control their own accounts by means of voting.
We’ll create two accounts, bob and alice . When creating an account, we specify the public key associated with that account. I’ve include example public keys below, but in order to import these accounts into Scatter, you must know the associated private keys. You can create your own EOS public key private key pairing using cleos, cleos wallet create_key --to-console, using an EOS key pairing generator online, or by going the long route, and creating your own EOS key generator with its own frontend you host locally.
We use the cleos command create account, using the eosio account, by specifying the account name and public key associated with that name.
cleos create account eosio bob EOS5T6c3EbR59YLEW3RXUyoy7rcqLd3hShkZJy8NfHdaP7EeEwVCJ
cleos create account eosio alice EOS5T6c3EbR59YLEW3RXUyoy7rcqLd3hShkZJy8NfHdaP7EeEwVCJ
You should output similar to the following:
powershell executed transaction: 40c605006de… 200 bytes 153 us # eosio <= eosio::newaccount
The token symbol can actually be any symbol, including EOS. We’ll create an EOS token supply. EOS has a total supply of 1,018,971,167.0000. Let’s use that.
cleos push action eosio.token create ‘[ “eosio”, “1018971167.0000 EOS”]’ -p eosio.token@active
Now, we have an EOS supply in our testnet. Let’s some circulate.
Issue Tokens
The issue function takes in the account we’re issuing to, the amount, and a message or memo.
cleos push action eosio.token issue '[ "alice", "10000.0000 EOS", "memo" ]' -p eosio@active
The amount issued is our circulating supply. The circulating supply of EOS in the mainnet at the time of writing is 922,271,161 EOS, much higher than 10,000 EOS. The circulating supply affects RAM prices, which may be important later once if you choose to deploy the system contract which deals with RAM. A low supply means a lot of RAM can be bought at very low EOS amounts. There are 4 decimals to EOS, meaning if the supply was low enough, you’d run into an error buying RAM where it would be impossible to buy smaller amounts of RAM, as doing so would take less than 4 decimals of EOS.
Regardless, now that we have a circulating supply, we can move EOS around.
Transfer Tokens
We previously made another account named bob. Let us transfer to that account from alice’s account.
cleos push action eosio.token transfer '[ "alice", "bob", "25.0000 EOS", "m" ]' -p alice@active
Now, if you added both alice and bob inside of Scatter, you should see their accounts containing EOS.
Done!
We have a testnet with accounts containing EOS available within Scatter. Now, if we develop a dApp with EOS, we can test it in our testnet for free before we commit to deploying on the mainnet. You can look up the Scatter documentation for learning how to have a client interact with Scatter.
That’s everything you’ll need, unless what you do requires the remaining eosio.contracts.
Now, our testnet isn’t exactly the same as the mainnet. This can be good or bad, depending on your needs. The mainnet, for example, requires a fee for creating new accounts. Right now, we can create as many free named accounts as we’d like with names of any character count. However, the mainnet limits even paid account creation to a fixed number of characters.
But some projects require more realistic configurations. For example, if you plan on creating an app that creates new accounts, you’ll need account creation functionality that mimics the mainnet, which means you’ll need to deploy the eosio.system smart contract.
The process for deploying another smart contract at this stage is the same as it was for the token contract. For this example, we’ll deploy the system contract, as it’s needed for dApp creation of accounts.
First, we need all required named accounts for the eosio.contracts.
Create an account for each of these names.
- eosio.bpay
- eosio.msig
- eosio.names
- eosio.ram
- eosio.ramfee
- eosio.saving
- eosio.stake
- eosio.token
- eosio.vpay
- eosio.rex
You can do so with this code, replacing the name with each.
cleos create account eosio eosio.<name> EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
For example, for eosio.ram:
cleos create account eosio eosio.ram EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
We’ll then deploy the eosio.system contract. The repository eosio.contracts contains a build.sh file, which builds all the contracts in that directory. We can run that and all contracts will be built for us.
For MacOS, this build requires cmake, which can be installed with Homebrew.
brew install cmake
Once we have the contract built, we can deploy it to our testnet. We set the system smart contract to the name eosio.
# needs the full path
cleos set contract eosio CONTRACTS_DIR/build/contracts/eosio.system --abi eosio.system.abi -p eosio@active
The eosio.system contract must be initialized after being deployed.
cleos push action eosio init '[0, "4,EOS"]' -p eosio@active
This can be undone if you’d like, but you’ll need to re-initiate your testnet almost from scratch.
Either way, our testnet is more like the mainnet.
Published at Mon, 08 Jul 2019 02:02:30 +0000
