·註冊bp時,需要錢包賬戶最低充值100個eos作為註冊費
1.同步節點部署
基於linux作業系統 ubuntu 16.04版本 原力eos原始碼部署方案,docker部署請參考https://github.com/eosforce/genesis
1. 下載原始碼
apt-get update && apt-get install -y git wget
git clone https://github.com/eosforce/eosforce.git eosforce
2. 執行如下命令安裝原力eos
cd eosforce && git submodule update --init --recursive && ./eosio_build.sh
mkdir -p ~/.local/share/eosio/nodeos/config
curl https://raw.githubusercontent.com/eosforce/genesis/master/genesis.json -o ~/.local/share/eosio/nodeos/config/genesis.json
cp build/contracts/eosio.token/eosio.token.abi build/contracts/eosio.token/eosio.token.wasm ~/.local/share/eosio/nodeos/config
cp build/contracts/System/System.abi build/contracts/System/System.wasm ~/.local/share/eosio/nodeos/config
cp build/contracts/eosio.bios/eosio.bios.abi build/contracts/eosio.bios/eosio.bios.wasm ~/.local/share/eosio/nodeos/config
cp build/contracts/eosio.msig/eosio.msig.abi build/contracts/eosio.msig/eosio.msig.wasm ~/.local/share/eosio/nodeos/config
cd build && make install
3. config核心配置檔案獲取並修改(若想修改p2p地址請參考第二節)
wget http://download.aitimeout.site/config.ini
cp config.ini ~/.local/share/eosio/nodeos/config/
config.ini檔案需要修改2個地方:
第一個修改地方:p2p-server-address = ip:7894 (ip為公網伺服器ip,埠自行修改,注意防火牆要放行該埠)
第二個修改的地方,修改成自己的genesis.json路徑,用絕對路徑防止出錯:
genesis-json = "/root/.local/share/eosio/nodeos/config/genesis.json"
4. 啟動節點並測試
cd build/programs/nodeos && ./nodeos
開啟另一個終端檢視本地區塊高度及對比eos原力官方主網的出塊高度
檢視本地高度命令如下,並多次執行如下命令區塊高度為不斷增加,說明同步正常,直到高度和原力主網高度接近時,同步完成
cleos get info
開啟瀏覽器輸入如下地址檢視原力eos主網區塊高度
https://w1.eosforce.cn/v1/chain/get_info
其中head_block_num為區塊高度
2.BP節點部署
準備工作
生成一對公私鑰給BP節點使用,執行如下命令生成
cleos create key
執行結果如下:
Private key: 5KidVdxbLKbJo9QiTyrbYULNTdKFTzdCb9oZgdaWye2CZfXz2hC
Public key: EOS6Z4fD6isTKZwaeH6Req7QXZLK3Yvb2rQoTxefVcsGXaXsFrBap
其中 Private key為私鑰 Public key為公鑰, Private 注意Public key在後面註冊bp時用到,即執行updatebp
基於以上部署好的同步節點進行修改,只需修改2個地方:
config.ini修改如下:
第一修改的地方:
producer-name = bpname (bpname為你的bp的名稱)
第二修改地方:
signature-provider = EOSpubkey=KEY:EOSprivkey (其中EOSpubkey準備工作中生成的公鑰,EOSprivkey為準備工作中生成的私鑰)
啟動節點,執行如下命令
刪除舊的資料
rm -rf ~/.local/share/eosio/nodeos/data
啟動
cd build/programs/nodeos && ./nodeos
3.BP節點註冊
準備工作: 首先要註冊一個原力eos賬戶名,並需要給這個賬戶轉100個eos,註冊時需要註冊費,賬戶名必須和bp的名字一樣,也為bpname,這樣 就有了公鑰pub_key,私鑰pri_key,賬戶名 bpname(和bp的名字同名),這個步驟就不詳細介紹
建立一個錢包
cleos wallet create
結果如下:
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5HwhcFEfN2Up63iK5LfQwXX7FmkUNkwV1t4TG73tMNxj59YeQws"
生成預設的錢包,最後一行為錢包的密碼
匯入賬戶私鑰到錢包
cleos wallet import pri_key
執行命令進行註冊
cleos -u https://p1.eosforce.cn push action eosio updatebp '{"bpname":"bpname","block_signing_key":"block_signing_key","commission_rate":"commission_rate","url":"https://eosforce.io"}' -p bpname
註冊成功返回如下結果:
executed transaction: 34dbe8bb08d0f7c3d5a4453d1e068e35f03c96f25d200c4e2a795e6aec472d60 160 bytes 6782 us
# eosio <= eosio::transfer {"from":"eosforce","to":"user1","quantity":"10.0000 EOS","memo":"my first transfer"}
warning: transaction executed locally, but may not be confirmed by the network yet
其中bpname 為bp的名稱。block_signing_key為BP的公鑰,commission_rate為佣金比例,設定3000,就是給使用者分紅70%,bp為30%,詳細介紹可以參考 https://github.com/eosforce/contracts/tree/master/System
最後如何檢驗出塊
出塊的2個條件:
·投票後排名前23名,可出塊
·本地bp節點同步已完成
可以下載我們的eosforce錢包並安裝,檢視自己的BP有沒有出塊 (錢包下載地址:https://github.com/eosforce/wallet-desktop/releases)
這裡要特別注意的是 --config-dir eosforce要求這個目錄下包含以下檔案:
config
├── System.abi
├── System.wasm
├── eosio.token.abi
├── eosio.token.wasm
├── config.ini
└── genesis.json
因為我們使用命令列引數,所以config.ini留一個空檔案即可
以下是個例子:
./nodeos \
--blocks-dir ./nodes/20-biosbpt/blocks \
--config-dir ./nodes/20-biosbpt/../../config \
--data-dir ./nodes/20-biosbpt \
--http-server-address 127.0.0.1:8020 \
--p2p-listen-endpoint 127.0.0.1:9020 \
--max-clients 33 \
--p2p-max-nodes-per-host 33 \
--enable-stale-production \
--producer-name biosbpt \
--signature-provider=EOS5bijTJg8ZkGNTuL3VfMcMc3bYdLtZ1faJJPYHRB1ShDZLtkeRY=KEY:5Jgau5mVjCiGrTGrvLr9YcyWfWdWWTrPYVwxUhgaRc5ixKWCCff \
--plugin eosio::http_plugin \
--plugin eosio::chain_api_plugin \
--plugin eosio::producer_plugin \
--p2p-peer-address localhost:9001
注意 啟動測試節點的時候,我們可以不是特別的注意安全問題,所以這裡啟動plugin都是全節點,生產環境中的超級節點需要注意安全問題。
這麼長的命令肯定不適合手動輸入,可以寫指令碼來啟動,最後我們使用python做一個啟動指令碼。
3. 啟動步驟
3.1 編譯eosforce
獲取程式碼:
git clone https://github.com/eosforce/eosforce.git
編譯:
cd eosforce
./eosio_build.sh
注意指令碼執行過程中會有幾次確認,注意透過。
成功會有以下提示:
( ____ \( ___ )( ____ \\__ __/( ___ )
| ( \/| ( ) || ( \/ ) ( | ( ) |
| (__ | | | || (_____ | | | | | |
| __) | | | |(_____ ) | | | | | |
| ( | | | | ) | | | | | | |
| (____/\| (___) |/\____) |___) (___| (___) |
(_______/(_______)\_______)\_______/(_______)
EOSIO has been successfully built. 00:12:35
To verify your installation run the following commands:
export PATH=${HOME}/opt/mongodb/bin:$PATH
/home/fy/opt/mongodb/bin/mongod -f /home/fy/opt/mongodb/mongod.conf &
cd /home/fy/projects/eosforce_gen/build; make test
For more information:
EOSIO website: https://eos.io
EOSIO Telegram channel @ https://t.me/EOSProject
EOSIO resources: https://eos.io/resources/
EOSIO Stack Exchange: https://eosio.stackexchange.com
EOSIO wiki: https://github.com/EOSIO/eos/wiki
這裡要注意的是,如果要執行test,最好確認關閉所有 nodeos 程序,否則會引起衝突
編譯結果預設的位置是 eosforce/build
為了不汙染全域性環境而引起一些錯誤,不建議使用 make install。
3.2 配置
為了方便啟動,這裡把節點工作目錄設定為 eosforce/build/testrun/, 相應的配置檔案目錄為 eosforce/build/testrun/config/
cd ./build
mkdir testrun
首先生成 genesis.json 這裡eosforce提供了一個工具,便於隨機生成所有超級節點的key
cd testrun
../programs/genesis/genesis
這時目錄下會生成以下檔案:
·config.ini 生成的超級節點key,便於複製到config.ini中
·genesis.json 生成的創始配置,我們後續就使用這個配置
·key.json 對應超級節點賬戶公鑰的私鑰
·sigkey.json 超級節點簽名用的公鑰對應的私鑰,後面會使用這個來啟動nodeos
這裡注意區分超級節點 賬戶key 和 sign_key, 啟動超級節點需要使用sign_key作為signature-provider配置。
對於genesis.json,我們直接移動進config目錄下:
mkdir ./config
mv ./genesis.json ./config/
複製需要的合約檔案進入config,同時建立一個空的config.ini, 注意 : eosforce所使用的合約是 eosforce/contracts/System 和 eosforce/contracts/eosio.token, 不是 不是 不是 eosforce/contracts/eosio.system
cp ../contracts/eosio.token/eosio.token.abi ./config/
cp ../contracts/eosio.token/eosio.token.wasm ./config/
cp ../contracts/System/System.abi ./config/
cp ../contracts/System/System.wasm ./config/
echo "" > ./config/config.ini
這時config下有如下檔案
config.ini eosio.token.abi eosio.token.wasm genesis.json System.abi System.wasm
3.3 啟動超級節點
完成配置之後可以啟動超級節點,這裡我們啟動三個節點, 由於第0屆超級節點是由genesis.json中指定的,我們啟動時需要對應genesis.json中的sign_key啟動超級節點, 這裡我們啟動 biosbpa biosbpb biosbpc三個節點。
在genesis.json中配置如下:
{
"initial_timestamp": "2018-05-28T12:00:00.000",
"initial_key": "EOS1111111111111111111111111111111114T1Anm",
...
"initial_configuration": { ... },
"initial_account_list": [{
"key": "EOS5XLWw7xu6qR1yqCCYqxYEMggCyKPWUTDyAjA1pgECFtcd39G41",
"asset": "1.0000 EOS",
"name": "biosbpa"
}],
"initial_producer_list": [{
"name": "biosbpa",
"bpkey": "EOS63o5TEdLsQrxFTUobiDupHQMX8K5pEs7PPk91afmpkrkiprokc",
"commission_rate": 0,
"url": ""
}]
}
initial_account_list中是初始賬號的列表,key是賬號公鑰,對應之前生成的key.json中的私鑰 initial_producer_list是超級節點的列表,bpkey對應的私鑰在之前生成的sigkey.json中
需要注意的是,eosforce啟動之後會處理b1賬戶,所以為了防止一直報錯,需要在initial_account_list中新增一個name為b1的賬戶。 否則會報以下錯誤:
2861606ms thread-0 controller.cpp:875 push_transaction ] -------call onfee function tx
2862013ms thread-0 wasm_interface.cpp:933 eosio_assert ] message: b1 is not found in accounts table
2862013ms thread-0 controller.cpp:888 push_transaction ] ---trnasction exe failed--------trace: {"id":"13a4c6b68425acb4fa4aae0d2e92fcb557939fa1f4b2e46228025bc8560b597f","elapsed":0,"net_usage":0,"scheduled":false,"action_traces":[{"receipt":{"receiver":"","act_digest":"0000000000000000000000000000000000000000000000000000000000000000","global_sequence":0,"recv_sequence":0,"auth_sequence":[],"code_sequence":0,"abi_sequence":0},"act":{"account":"","name":"","authorization":[],"data":""},"elapsed":0,"cpu_usage":0,"console":"","total_cpu_usage":0,"trx_id":"0000000000000000000000000000000000000000000000000000000000000000","inline_traces":[]}],"failed_dtrx_trace":null,"except":{"code":3050003,"name":"eosio_assert_message_exception","message":"eosio_assert_message assertion failure","stack":[{"context":{"level":"error","file":"wasm_interface.cpp","line":934,"method":"eosio_assert","hostname":"","thread_name":"thread-0","timestamp":"2018-07-13T03:47:42.013"},"format":"assertion failure with message: ${s}","data":{"s":"b1 is not found in accounts table"}},{"context":{"level":"warn","file":"apply_context.cpp","line":60,"method":"exec_one","hostname":"","thread_name":"thread-0","timestamp":"2018-07-13T03:47:42.013"},"format":"","data":{"_pending_console_output.str()":""}}]}}
2862014ms thread-0 controller.cpp:875 push_transaction ] -------call onfee function tx
也可以啟動主網之後手動建立一個b1賬戶
這裡我們啟動超級節點需要對應超級節點的name,bpkey和在sigkey.json中的sig_key, 分別在下面的{name},{bpkey},{sig_key}
./nodeos --blocks-dir ./nodes/biosbpa/blocks --config-dir ./config --data-dir ./nodes/biosbpa --http-server-address 127.0.0.1:8021 --p2p-listen-endpoint 127.0.0.1:9021 --max-clients 64 --p2p-max-nodes-per-host 64 --enable-stale-production --producer-name biosbpa --signature-provider={biosbpa-bpkey}=KEY:{biosbpa-sig_key} --plugin eosio::http_plugin --plugin eosio::chain_api_plugin --plugin eosio::producer_plugin
./nodeos --blocks-dir ./nodes/biosbpb/blocks --config-dir ./config --data-dir ./nodes/biosbpb --http-server-address 127.0.0.1:8022 --p2p-listen-endpoint 127.0.0.1:9022 --max-clients 64 --p2p-max-nodes-per-host 64 --enable-stale-production --producer-name biosbpb --signature-provider={biosbpb-bpkey}=KEY:{biosbpb-sig_key} --plugin eosio::http_plugin --plugin eosio::chain_api_plugin --plugin eosio::producer_plugin --p2p-peer-address localhost:9021
./nodeos --blocks-dir ./nodes/biosbpc/blocks --config-dir ./config --data-dir ./nodes/biosbpc --http-server-address 127.0.0.1:8023 --p2p-listen-endpoint 127.0.0.1:9023 --max-clients 64 --p2p-max-nodes-per-host 64 --enable-stale-production --producer-name biosbpc --signature-provider={biosbpc-bpkey}=KEY:{biosbpc-sig_key} --plugin eosio::http_plugin --plugin eosio::chain_api_plugin --plugin eosio::producer_plugin --p2p-peer-address localhost:9021 --p2p-peer-address localhost:9022
注意其中的 --p2p-peer-address 依照啟動順序監聽已經啟動的節點
如果啟動成功,可以看到節點出塊日誌
需要注意的是,EOS中如果要出塊的節點沒有啟動,則這一塊會輪空,依然會等待出塊的間隔,直到能出塊的節點出塊, eosforce程式碼中預設出塊間隔是3s,這意味著a,b,c三個節點各自出塊之後,會等待 20 * 3 = 60s之後,a節點才會出下一個塊
3.4 驗證執行合約
參見 https://github.com/eosforce/contracts/tree/master/System#command-reference 連線之前設定的http-server-address 127.0.0.1:8022,例如使用如下執行:
./cleos -u http://127.0.0.1:8022 get table eosio eosio bps
獲取超級節點列表
3.5 使用客戶端錢包連線測試網
TODO
4. 透過python指令碼啟動
這個指令碼改寫自 eosforce/tutorials/bios-boot-tutorial/bios-boot-tutorial.py 可以方便的在單機上一鍵啟動23個節點構成測試網。
4.1 指令碼
#!/usr/bin/env python3
import argparse
import json
import os
import re
import subprocess
import sys
import time
args = None
logFile = None
unlockTimeout = 999999999
def jsonArg(a):
return " '" + json.dumps(a) + "' "
def run(args):
print('bios-boot-tutorial.py:', args)
logFile.write(args + '\n')
if subprocess.call(args, shell=True):
print('bios-boot-tutorial.py: exiting because of error')
sys.exit(1)
def retry(args):
while True:
print('bios-boot-tutorial.py:', args)
logFile.write(args + '\n')
if subprocess.call(args, shell=True):
print('*** Retry')
else:
break
def background(args):
print('bios-boot-tutorial.py:', args)
logFile.write(args + '\n')
return subprocess.Popen(args, shell=True)
def sleep(t):
print('sleep', t, '...')
time.sleep(t)
print('resume')
def makeGenesis():
run('rm -rf ' + os.path.abspath(args.config_dir))
run('mkdir -p ' + os.path.abspath(args.config_dir))
run('mkdir -p ' + os.path.abspath(args.config_dir) + '/keys/' )
run('cp ' + os.path.abspath(args.contracts_dir) + '/eosio.token/eosio.token.abi ' + os.path.abspath(args.config_dir))
run('cp ' + os.path.abspath(args.contracts_dir) + '/eosio.token/eosio.token.wasm ' + os.path.abspath(args.config_dir))
run('cp ' + os.path.abspath(args.contracts_dir) + '/System/System.abi ' + os.path.abspath(args.config_dir))
run('cp ' + os.path.abspath(args.contracts_dir) + '/System/System.wasm ' + os.path.abspath(args.config_dir))
run('echo "" > ' + os.path.abspath(args.config_dir) + '/config.ini')
run('../programs/genesis/genesis')
run('mv ./genesis.json ' + os.path.abspath(args.config_dir))
run('mv ./key.json ' + os.path.abspath(args.config_dir) + '/keys/')
run('mv ./sigkey.json ' + os.path.abspath(args.config_dir) + '/keys/')
def addB1Account():
run(args.cleos + 'create account eosforce b1 ' + initAccounts[len(initAccounts) - 1]['key'])
def startWallet():
run('rm -rf ' + os.path.abspath(args.wallet_dir))
run('mkdir -p ' + os.path.abspath(args.wallet_dir))
background(args.keosd + ' --unlock-timeout %d --http-server-address 127.0.0.1:6666 --wallet-dir %s' % (unlockTimeout, os.path.abspath(args.wallet_dir)))
sleep(.4)
run(args.cleos + 'wallet create')
def importKeys():
keys = {}
for a in initAccountsKeys:
key = a[1]
if not key in keys:
keys[key] = True
# note : new develop eosforce change this command to wallet import --key pk
# so need change this cmd
run(args.cleos + 'wallet import key ' + key)
def startNode(nodeIndex, bpaccount, key):
dir = args.nodes_dir + ('%02d-' % nodeIndex) + bpaccount['name'] + '/'
run('rm -rf ' + dir)
run('mkdir -p ' + dir)
otherOpts = ''.join(list(map(lambda i: ' --p2p-peer-address localhost:' + str(9001 + i), range(nodeIndex - 1))))
if not nodeIndex: otherOpts += (
' --plugin eosio::history_plugin'
' --plugin eosio::history_api_plugin'
)
print('bpaccount ', bpaccount)
print('key ', key, ' ', key[1])
cmd = (
args.nodeos +
' --blocks-dir ' + os.path.abspath(dir) + '/blocks'
' --config-dir ' + os.path.abspath(dir) + '/../../config'
' --data-dir ' + os.path.abspath(dir) +
' --http-server-address 127.0.0.1:' + str(8000 + nodeIndex) +
' --p2p-listen-endpoint 127.0.0.1:' + str(9000 + nodeIndex) +
' --max-clients ' + str(maxClients) +
' --p2p-max-nodes-per-host ' + str(maxClients) +
' --enable-stale-production'
' --producer-name ' + bpaccount['name'] +
' --signature-provider=' + bpaccount['bpkey'] + '=KEY:' + key[1] +
' --plugin eosio::http_plugin'
' --plugin eosio::chain_api_plugin'
' --plugin eosio::producer_plugin' +
otherOpts)
with open(dir + '../' + bpaccount['name'] + '.log', mode='w') as f:
f.write(cmd + '\n\n')
background(cmd + ' 2>>' + dir + '../' + bpaccount['name'] + '.log')
def startProducers(inits, keys):
for i in range(0, len(inits)):
startNode(i + 1, initProducers[i], keys[i])
def listProducers():
run(args.cleos + 'get table eosio eosio bps')
def stepKillAll():
run('killall keosd nodeos || true')
sleep(1.5)
def stepStartWallet():
startWallet()
importKeys()
def stepStartProducers():
startProducers(initProducers, initProducerSigKeys)
sleep(1)
addB1Account()
sleep(args.producer_sync_delay)
def stepLog():
run('tail -n 1000 ' + args.nodes_dir + 'biosbpa.log')
listProducers()
# Command Line Arguments
parser = argparse.ArgumentParser()
commands = [
('k', 'kill', stepKillAll, True, "Kill all nodeos and keosd processes"),
('w', 'wallet', stepStartWallet, True, "Start keosd, create wallet, fill with keys"),
('P', 'start-prod', stepStartProducers, True, "Start producers"),
('l', 'log', stepLog, True, "Show tail of node's log"),
]
parser.add_argument('--contracts-dir', metavar='', help="Path to contracts directory", default='../contracts/')
parser.add_argument('--cleos', metavar='', help="Cleos command", default='../programs/cleos/cleos --wallet-url http://localhost:6666 ')
parser.add_argument('--nodeos', metavar='', help="Path to nodeos binary", default='../programs/nodeos/nodeos')
parser.add_argument('--nodes-dir', metavar='', help="Path to nodes directory", default='./nodes/')
parser.add_argument('--keosd', metavar='', help="Path to keosd binary", default='../programs/keosd/keosd')
parser.add_argument('--log-path', metavar='', help="Path to log file", default='./output.log')
parser.add_argument('--wallet-dir', metavar='', help="Path to wallet directory", default='./wallet/')
parser.add_argument('--config-dir', metavar='', help="Path to config directory", default='./config')
parser.add_argument('--producer-sync-delay', metavar='', help="Time (s) to sleep to allow producers to sync", type=int, default=10)
parser.add_argument('-a', '--all', action='store_true', help="Do everything marked with (*)")
parser.add_argument('-H', '--http-port', type=int, default=8001, metavar='', help='HTTP port for cleos')
for (flag, command, function, inAll, help) in commands:
prefix = ''
if inAll: prefix += '*'
if prefix: help = '(' + prefix + ') ' + help
if flag:
parser.add_argument('-' + flag, '--' + command, action='store_true', help=help, dest=command)
else:
parser.add_argument('--' + command, action='store_true', help=help, dest=command)
args = parser.parse_args()
args.cleos += '--url http://localhost:%d ' % args.http_port
logFile = open(args.log_path, 'a')
logFile.write('\n\n' + '*' * 80 + '\n\n\n')
makeGenesis()
with open(os.path.abspath(args.config_dir) + '/genesis.json') as f:
a = json.load(f)
initAccounts = a['initial_account_list']
initProducers = a['initial_producer_list']
with open(os.path.abspath(args.config_dir) + '/keys/sigkey.json') as f:
a = json.load(f)
initProducerSigKeys = a['keymap']
with open(os.path.abspath(args.config_dir) + '/keys/key.json') as f:
a = json.load(f)
initAccountsKeys = a['keymap']
maxClients = len(initProducers) + 10
haveCommand = False
for (flag, command, function, inAll, help) in commands:
if getattr(args, command) or inAll and args.all:
if function:
haveCommand = True
function()
if not haveCommand:
print('bios-boot-tutorial.py: Tell me what to do. -a does almost everything. -h shows options.')
4.2 執行說明
py指令碼預設的執行位置在 eosforce/build/XXX 目錄下, ‘XXX’可以任意指定
執行即可:
chmod u+x ./bios_boot_eosforce.py
./bios_boot_eosforce.py
成功後會查詢所有當前bp,各個節點日誌在 eosforce/build/XXX/nodes/ 目錄下