《虛擬幣交易平台(區塊鏈)》 ——上 【發行區塊鏈代幣】
關於對於區塊鏈 或者 比特幣還沒有一個基礎概念的就自行百度吧,什么“去中心化”,“挖礦”,“POW”,等等等等,亂七八糟的東西
就隨便找個三分鍾科普視頻看一下就行了。我們這邊將就直接進入正題,如何發行一個區塊代幣。
說到代幣,始終繞不過比特幣,關於比特幣有幾個點還是要說一下:
1,首先比特幣的代碼是開源的,所以很多山寨幣修改比特幣加密算法然后就發行自己的代幣,很多沒有創新意義的山寨幣是沒有價值的。
2,比特幣是基於區塊鏈技術的首個應用。 更准確的說在沒有“區塊鏈”這個名詞之前把“BitCoin”代表比特幣,而“bitCoin”代表實現比特幣的技術(大小寫不同)。
3,比特幣的技術“區塊鏈” 從最本質來說是一種思想,用什么語言去實現它是都可以的,哪怕是Java,C#。但常用的還是C/C++。
4,比特幣不代表區塊鏈,比特幣的區塊鏈技術有很多不足的地方,比如:不具有“圖靈完備”。 就是他不能像Android一樣,基於他開發應用。
5,第一條里面說沒有競爭優勢的山寨幣是沒有價值的。這種就是通常用來做ICO的“空氣幣”,而所謂的ICO今天基本可以看做割韭菜的代名詞現在國家已經禁止了ICO。
而有競爭優勢的才有價值比如擴容了區塊的萊特幣(LTC)。比如以“智能合約”著稱的 以太坊(以太坊是區塊鏈技術,代幣是以太幣,另外還有硬分叉的以太經典)。
說了這么多廢話,今天我們這一篇只要討論的還是如何發幣,直接來點干貨?
總的來說2種方式:
A: 直接下載比特幣的源代碼,如何能看懂C/C++ 就沒難度,直接改掉名字就行了。
具體怎么搞呢?非常簡單:https://github.com/bitcoin/bitcoin 直接上GITHub下載 然后改吧。
B:前面說了比特幣的區塊鏈是不具備圖靈完備的,所以有些將區塊鏈封裝成平台的我們只要基於這個平台
開發自己的代幣應用就行了。比如: 超級賬本(hyperledger), 還有前面提到的以太坊(Ethereum)。
下面我會重點講一下以太坊。
===================================華麗的分割線==========================================
講到這里我們才是真的切入正題了,利用以太坊發幣。關於以太坊是什么?什么是智能合約? 這些能百度到的概念性東西
我就不做百度的搬運工了,我直接講實操的部分。
首先我們可以下載需要我們需要下載以太坊的錢包客戶端:
其實以太坊的錢包客戶端 主要的都是Geth這個工具, Geth是一定要下載的 Ethereum Wallet 和 Mist 都是基於geth做了一個圖形化界面。
注意,重點來了!以太坊是基於go語言發開的,本身我們也可以下載以太坊的源碼然后像改比特幣源碼一樣去改成自己的區塊鏈,
Github的以太坊源碼鏈接: https://github.com/ethereum/go-ethereum
但是回歸到本質是上來說還是那句話:首先要能看的懂,其次改完之后要有競爭力。
我們貼一下錢包客戶端的圖,整篇博客都是文字 就太不利於閱讀了,我這里貼的 Ethereum Wallet,推薦使用Ethereum Wallet。
默認以太坊錢包客戶端會連接上真實以太坊“主鏈”也叫公有鏈,所以就在一直同步區塊,這就很費事了,以太坊有專門開發人員提供測試環境也就是測試鏈(Rinkeby)
這個我們晚點再說。
如果利用以太坊發幣第一種方式是,直接下載以太坊源碼修改以太坊的話,那第二種辦法就是利用以太坊的區塊鏈技術發布一個私有鏈!
怎么做?我們先嘗試着發布一個自己的私有鏈。
步驟如下:
1,下載geth錢包客戶端:
2,下載圖形化錢包客戶端:
3,自己創建一個私有鏈需要一個創世文件genesis.json,這里我直接提供了。(geth從1.7版本開始創世文件要加config參數)
{
"config"
: {
"chainId"
: 15,
"homesteadBlock"
: 0,
"eip155Block"
: 0,
"eip158Block"
: 0
},
"coinbase"
:
"0x0000000000000000000000000000000000000000"
,
"difficulty"
:
"0x40000"
,
"extraData"
:
""
,
"gasLimit"
:
"0xffffffff"
,
"nonce"
:
"0x0000000000000042"
,
"mixhash"
:
"0x0000000000000000000000000000000000000000000000000000000000000000"
,
"parentHash"
:
"0x0000000000000000000000000000000000000000000000000000000000000000"
,
"timestamp"
:
"0x00"
,
"alloc"
: { }
}
將這個文件,保存到txt,改名叫genesis.json,當然名字可以自己決定。這就是一個普通的json文件。
里面的字段是什么意思呢? 我來解釋一下(其實也是百度查的):
參數名稱 | 參數描述 |
---|---|
mixhash | 與nonce配合用於挖礦,由上一個區塊的一部分生成的hash。注意他和nonce的設置需要滿足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章節所描述的條件。 |
nonce | nonce就是一個64位隨機數,用於挖礦,注意他和mixhash的設置需要滿足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章節所描述的條件。 |
difficulty | 設置當前區塊的難度,如果難度過大,cpu挖礦就很難,這里設置較小難度 |
alloc | 用來預置賬號以及賬號的以太幣數量,因為私有鏈挖礦比較容易,所以我們不需要預置有幣的賬號,需要的時候自己創建即可以。 |
coinbase | 礦工的賬號,隨便填 |
timestamp | 設置創世塊的時間戳 |
parentHash | 上一個區塊的hash值,因為是創世塊,所以這個值是0 |
extraData | 附加信息,隨便填,可以填你的個性信息 |
gasLimit | 該值設置對GAS的消耗總量限制,用來限制區塊能包含的交易信息總和,因為我們是私有鏈,所以填最大。 |
這里暫時不要去懂太多,反正知道 我們需要一個創世文件genesis.json即可。
4,將創世文件保存下來,我這里放到C:\Program Files\Geth, 我這里是因為Geth客戶端 安裝就在C盤,如果C盤空間不是很足就不建議安裝在C盤了
正式環境的主鏈現在有60G左右,很占空間。
5,運行命令通過cmd命令運行。 直接打開geth就鏈接到主鏈了,默認是主鏈,所以我們通過命令加載創世文件。
geth –datadir “%cd%\chain” init genesis.json
有可能會出現找不到文件的狀況,所以我們要定位一下geth的目錄。
創世區塊加載成功了!
6, 再通過命令來啟動私有鏈,並進入控制台:
geth --identity "Nearetherum" --rpc --rpccorsdomain "*" --datadir “%cd%\chain” --port "30303" --rpcapi "db,eth,net,web3" --networkid 11100 console
私有鏈啟動成功了!
我們來看看geth的一些基本參數:
參數描述
identity:區塊鏈的標示,隨便填寫,用於標示目前網絡的名字
init:指定創世塊文件的位置,並創建初始塊
datadir:設置當前區塊鏈網絡數據存放的位置
port:網絡監聽端口
rpc:啟動rpc通信,可以進行智能合約的部署和調試
rpcapi:設置允許連接的rpc的客戶端,一般為db,eth,net,web3
networkid:設置當前區塊鏈的網絡ID,用於區分不同的網絡,是一個數字
console:啟動命令行模式,可以在Geth中執行命令
nodiscover:禁止被網絡中其它節點發現,需要手動添加該節點到網絡
執行 personal命令,這個私有鏈里沒有任何錢包
我們創建一個錢包賬戶試試:
personal.newAccount("123456")
再執行personal:
賬戶創建成功了。
好了,到這里我們的私有鏈就創建的差不多了,接下來就是在我們的私有鏈里我們要運用起來,就得有人挖礦,挖礦其實就是記賬。
輸入命令:miner.start() 或者miner.start(1) 。這里miner.start(1) 就是一個線程挖礦的意思。 這里停止挖礦是:miner.stop()
挖礦就開始了。
由於我們在挖礦也就是記賬,所以區塊會慢慢增加,占用的空間也會越來也多。
注意:挖礦挖到的ether幣會默認保在第一個賬戶中即eth.acccounts[0]中,所以要先創建一個錢包!
7,geth 不要關讓他繼續挖礦,我們打開圖形化界面看看,這時會發現右上角有一個PRIVATE-NET!
PRIVATE-NET,意思就是啟動鏈接的是私有鏈網絡。 如果我們沒有啟動私有鏈默認是鏈接主鏈了。
后面我們還會介紹以太坊的測試環境Rinkeby。
我們直接點擊運行,錢包客戶端,這時候回發現錢包客戶端里面有一個錢包地址,這就是我們剛剛在Geth里面創建的錢包。
看看 是不是我們上面創建的錢包,這里我們里面就有私有鏈的以太坊了。這15個以太幣就是我們剛剛挖礦得到了,我們繼續開啟挖礦,就可以繼續獲得以太幣!
不過這是私有鏈的。當然我們可以在私有鏈上部署智能合約!
這里就比我們直接拿以太坊的源碼去改方便太多了。直接用以太坊發布自己的私有鏈,發布自己的代幣了!
不過缺點是私有鏈我們需要別人來同步我們的區塊鏈,並且還要有人來挖礦記賬以及確認交易,如果停止挖礦的話,就不會再產生以太幣,智能合約也沒用了
說白了就是沒人挖礦就沒有新的區塊來產生。
===========================================華麗的分割線===================================
我們來回顧一下以上我們講了三種發行代幣的方式:
1,上GitHub上下載比特幣的源碼然后進行修改。缺點:需要懂C/C++,並且能充分理解比特幣思想然后才能改動。
並且比特幣底層區塊不具備圖靈完備,從長遠來說也就只能發個幣。所以不推薦!
2,以太坊同樣是開源的,我們可以上Github下載以太坊的源碼然后修改,優點是以太坊是可以編程的,但同樣需要精通Go語言並且
要去改底層算法,所以不推薦!
3,利用以太坊技術發布一個私有鏈/聯盟鏈。缺點是需要人挖礦記賬。(這里說明一下比特幣,萊特幣都是需要人挖礦記賬的,以太幣也一樣。)
那么問題來了,有沒有不需要挖礦的,比如那些做ICO的圈錢割韭菜的,他們就根本沒有礦工,是怎么回事?
接下來才是我整篇博客要寫的重點? 基於“智能合約”發行代幣!
寫了這么多才寫到重點,上面寫的那些都基本是廢話了。還是那句話,我這里更多的就寫實操的東西,關於概念性的玩意,我就不做百度
的搬運工了。在此之前我們先記住幾個網站:
以太坊官網:https://www.ethereum.org/
以太坊愛好者:http://ethfans.org/
以太坊區塊瀏覽器:https://etherscan.io/
以太坊測試環境Rinkeby狀態網:https://www.rinkeby.io/
=======================================華麗的分割線==============================
正文開始,首先我們打開以太坊錢包客戶端,可能有的人會卡一下,沒關系因為錢包客戶端會在本地創建區塊,並且開始同步一部分區塊。
打開之后我們看到第一個選擇:
稍微懂一點英文我們都能看明白什么意思,Main Network 就是主鏈,Test Network 就是測試鏈。Main Network也就是真實的以太坊環境,我們可以嘗試進主鏈看看。不過主鏈現在區塊應該有60多G,所以同步時間會比較久。
而且以太幣現在已經漲到了5千大洋一個,我們基於以太坊部署智能合約 發型代幣是需要“以太幣”的。 這對於我們新手來說,反復嘗試部署,不可能去交易所買那么多以太幣來測試。(可以嘗試挖礦獲得以太坊,但是太難!)
所以,我們用測試環境“Rinkeby”。本身以太坊有幾個測試鏈Rinkeby,只是其中之一!(比如還有:ropsten 但是不推薦使用了)
我們創建一個在Rinkeby 測試鏈的以太坊錢包:
正常情況下的話,這里創建完錢包之后就一步一步進入到錢包客戶端主界面了,但是有可能會出現鏈接不上Rinkeby的故障
比如我這種:
這是什么原因呢?其實是因為我們本地沒有加載Rinkeby的創始區塊,並且客戶端也不知道去哪里同步區塊。這個時候我們就要用到我們
前面提到的那些網站,我們打開:https://www.rinkeby.io/ 訪問速度比較慢的就下載個翻牆軟件。
這里我們看到首先我們需要Rinkeby的創始區塊json,跟前面我們發私有鏈流程是一樣的,把Rinkeby.json 保存在本地geth目錄下。
(由於之前的文章是我昨天用筆記本寫的,今天我換了台式機所以我geth的目錄變成了d盤下,沒關系我們在cmd命令窗口里,定位一下目錄就行了)
然后流程是一樣的,上面我們看到https://www.rinkeby.io/#geth 里面有四個節點選擇,關於這四個節點要細講起來,就要講的東西比較多,這里我們就選第一個吧:Archive node 。
geth --datadir=$HOME/.rinkeby init rinkeby.json
然后使用同步全節點:
geth --networkid=4 --datadir=$HOME/.rinkeby --cache=1024 --syncmode=full --ethstats='demon28@163.com' --bootnodes=enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@52.169.42.101:30303
注意:--ethstats: 改成自己的郵箱,這個隨便填個郵箱就行,但是要改一下!上面那個demon28@163.com 是我的郵箱,要改成自己的!
這個時候再打開錢包客戶端就可以連接Rinkeby了! 我們會發現rinkeby的區塊要比以太坊主鏈要小好多,這里除了是測試環境以外還有一個原因,因為Rinkeby是不允許挖礦的。
如果,Rinkeby的測試環境允許挖礦的話,那測試環境的區塊就會越來越大,有可能測試環境甚至可能比主鏈區塊都大,那么問題來了!
前面我們說過通過部署智能合約發行代幣,是需要以太幣的,幾遍是測試環境也是,那么Rinkeby又不能挖礦,我們怎么獲得Rinkeby測試鏈下的以太幣?
其實很簡單!直接問以太坊要唄,夠直接吧! https://www.rinkeby.io/#faucet
在此之前,我們得先有一個接受Rinkeby以太幣的錢包地址,前面如果創建成功的,進入客戶端界面之后會有錢包地址顯示,如果沒有的就創建一下!
那么我們這里就創建了一個rinkeby錢包:
也可以像前面我們操作私有鏈一樣在geth里面操作,也是一樣的。圖形化界面只是封裝了一下而已!
接下來,我們繼續來問官網要 rinkeby的測試以太幣
看到這個有點懵是不? 我也是,我也沒明白上面要我填上面,起初我也以為只要填錢包地址就可以了,后來發現不是這么回事。
百度一下,才讀懂這句英文: Social network URL containing your Ethereum address ! (可能英文比較好的人沒有我這個問題,我是屬於英文比較不好的)
意思就是說:"給他一個網絡訪問地址,打開里面的內容是rinkeby錢包地址!" 雖然意思明白了,但是具體這么搞呢?
上面有說,用 “推脫” 或者 “谷歌+” 或者 “Facebook” 。 (都要翻牆,這個翻牆的問題就靠自己解決咯!)
其實我上一次要幣的時候用的github的gists,gists就相當於一個網絡記事本,雖然也要翻牆,但是github還是比較熟悉的,不過現在github不讓用了,所以我們今天我們嘗試用一下google+。
關於谷歌賬號怎么注冊,怎么登陸這個我就不說了。登陸后,相當於我們發朋友圈,發QQ說說一樣,發一條google+的消息就行了,如下圖:
然后把訪問地址復制!
再回到 https://www.rinkeby.io/#faucet然后直接要三個以太幣。
別要多了,本身這就是測試幣要多了沒用! 並且要的越多時間到賬的時間越久。上面也寫了,要3個的話到賬時間要8個小時!。
在這8個小時的等待時間里,我們可以讓Rinkeby的區塊慢慢同步。 一般睡一覺第二天就到了!
經過漫長的等待,終於rinkeby的區塊也同步完了,於此同時。我們索要的Rinkeby的測試幣也到賬了。
有沒有比較快的方式,也有! 直接加幾個以太坊的群,問群里的大神要1個就好! 我們這里寫的比較細,主要是把幾個源頭說清楚!
我們長話短說,測試幣到賬之后,我們就要部署智能合約了!
=====================================華麗的分割線==========================================
智能合約 是用solidity 這種腳本語言開發的,類似JavaScript 不是很復雜。 我們點擊錢包客戶端的 右上角的 Contracts (合約)
再選擇部署智能合約!
這里我直接提供一個官網的發行代幣智能合約: 官網文檔:https://ethereum.org/token
pragma solidity ^0.4.16; interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; } contract TokenERC20 { // Public variables of the token string public name; string public symbol; uint8 public decimals = 18; // 18 decimals is the strongly suggested default, avoid changing it uint256 public totalSupply; // This creates an array with all balances mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; // This generates a public event on the blockchain that will notify clients event Transfer(address indexed from, address indexed to, uint256 value); // This notifies clients about the amount burnt event Burn(address indexed from, uint256 value); /** * Constructor function * * Initializes contract with initial supply tokens to the creator of the contract */ function TokenERC20( uint256 initialSupply, string tokenName, string tokenSymbol ) public { totalSupply = initialSupply * 10 ** uint256(decimals); // Update total supply with the decimal amount balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes } /** * Internal transfer, only can be called by this contract */ function _transfer(address _from, address _to, uint _value) internal { // Prevent transfer to 0x0 address. Use burn() instead require(_to != 0x0); // Check if the sender has enough require(balanceOf[_from] >= _value); // Check for overflows require(balanceOf[_to] + _value > balanceOf[_to]); // Save this for an assertion in the future uint previousBalances = balanceOf[_from] + balanceOf[_to]; // Subtract from the sender balanceOf[_from] -= _value; // Add the same to the recipient balanceOf[_to] += _value; Transfer(_from, _to, _value); // Asserts are used to use static analysis to find bugs in your code. They should never fail assert(balanceOf[_from] + balanceOf[_to] == previousBalances); } /** * Transfer tokens * * Send `_value` tokens to `_to` from your account * * @param _to The address of the recipient * @param _value the amount to send */ function transfer(address _to, uint256 _value) public { _transfer(msg.sender, _to, _value); } /** * Transfer tokens from other address * * Send `_value` tokens to `_to` on behalf of `_from` * * @param _from The address of the sender * @param _to The address of the recipient * @param _value the amount to send */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { require(_value <= allowance[_from][msg.sender]); // Check allowance allowance[_from][msg.sender] -= _value; _transfer(_from, _to, _value); return true; } /** * Set allowance for other address * * Allows `_spender` to spend no more than `_value` tokens on your behalf * * @param _spender The address authorized to spend * @param _value the max amount they can spend */ function approve(address _spender, uint256 _value) public returns (bool success) { allowance[msg.sender][_spender] = _value; return true; } /** * Set allowance for other address and notify * * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it * * @param _spender The address authorized to spend * @param _value the max amount they can spend * @param _extraData some extra information to send to the approved contract */ function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) { tokenRecipient spender = tokenRecipient(_spender); if (approve(_spender, _value)) { spender.receiveApproval(msg.sender, _value, this, _extraData); return true; } } /** * Destroy tokens * * Remove `_value` tokens from the system irreversibly * * @param _value the amount of money to burn */ function burn(uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value); // Check if the sender has enough balanceOf[msg.sender] -= _value; // Subtract from the sender totalSupply -= _value; // Updates totalSupply Burn(msg.sender, _value); return true; } /** * Destroy tokens from other account * * Remove `_value` tokens from the system irreversibly on behalf of `_from`. * * @param _from the address of the sender * @param _value the amount of money to burn */ function burnFrom(address _from, uint256 _value) public returns (bool success) { require(balanceOf[_from] >= _value); // Check if the targeted balance is enough require(_value <= allowance[_from][msg.sender]); // Check allowance balanceOf[_from] -= _value; // Subtract from the targeted balance allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance totalSupply -= _value; // Update totalSupply Burn(_from, _value); return true; } }
====================================華麗的分割線=======================================
如果沒有rinkeby的測試以太幣,這里是不能部署智能合約的,這里也牽扯到一個“燃料” 的知識點。燃料在以太坊里面叫“gas”。
其實就是以太幣,但是他的單位比以太幣小很多很多。假如以太幣是一元的話,gas大概就是0.000001分錢。當然這個隨着以太坊的價格浮動的。
我們接着來部署發行代幣的智能合約:
再來輸入密碼確認:
回過頭來點開自己的錢包,就可以看到部署的智能合約,也就是我們發行的區塊鏈代幣,在等待區塊確認。 這里我們前面給的gas確認速度就會越快!
以太坊是目前區塊鏈中確認速度最快的,我們看到我們發行的Near幣 已經成功了。
我們嘗試着新建幾個賬戶相互之間用我們發行的NearCoin轉賬試試。
每次交易都要收手續費的,這個手續費就是挖礦人員獲得的收益之一。
到賬了··!!
另外,如果需要轉賬給別人,需要別人先添加觀察你的智能合約,就可以獲得了。
================================================華麗的分割線==============================================
最后再回顧一下說的四種發行代幣的方式:
1,修改比特幣源碼。
2,修改以太坊源碼。
3,發布私有鏈。
4,部署智能合約 (重點)。
行了,這篇博客寫了我兩天時間,中間有些概念我也不知道我理解的對不對。如果有理解錯誤的地方還望指正!
在下一篇的博客中,我將根據我的經驗來寫如何開發一個 “虛擬幣交易平台”。
如果您覺得這篇文章對您有幫助,請捐助:
好了,就到這里有興趣一起探討Winner框架的可以加我們QQ群:261083244。或者掃描左側二維碼加群。