This is because in the latest version the error message is suppressed if you start nodeos with --verbose-http-errors
option, you can see a more descriptive error message.
Rpc Error details is empty
Not producing block because I don't have the private key for EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
有人提问 config.ini中新增加的signature-provider和private key有什么区别,该用哪个?
根据signature-provider的注释(DEPRECATED - Use signature-provider instead) Tuple of [public key, WIF private key] (may specify multiple times) (eosio::producer_plugin)
private key将会废弃,被signature-provider替代。
对于两个键值的解析可查看下面producer_plugin.cpp
中的plugin_initialize
代码。
但是尝试直接将private key中的key替换到signature-provider 提示一下错误
1400500ms thread-0 producer_plugin.cpp:751 start_block ] Not producing block because I don't have the private key for EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
根据查看以下代码,分析(结论在最后)
eos_source_dir\plugins\producer_plugin\producer_plugin.cpp
void producer_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{ try {
my->_options = &options;
LOAD_VALUE_SET(options, "producer-name", my->_producers, types::account_name)
if( options.count("private-key") )
{
const std::vector<std::string> key_id_to_wif_pair_strings = options["private-key"].as<std::vector<std::string>>();
for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
{
try {
auto key_id_to_wif_pair = dejsonify<std::pair<public_key_type, private_key_type>>(key_id_to_wif_pair_string);
my->_signature_providers[key_id_to_wif_pair.first] = make_key_signature_provider(key_id_to_wif_pair.second);
auto blanked_privkey = std::string(std::string(key_id_to_wif_pair.second).size(), '*' );
wlog("\"private-key\" is DEPRECATED, use \"signature-provider=${pub}=KEY:${priv}\"", ("pub",key_id_to_wif_pair.first)("priv", blanked_privkey));
} catch ( fc::exception& e ) {
elog("Malformed private key pair");
}
}
}
if( options.count("signature-provider") ) {
const std::vector<std::string> key_spec_pairs = options["signature-provider"].as<std::vector<std::string>>();
for (const auto& key_spec_pair : key_spec_pairs) {
try {
auto delim = key_spec_pair.find("=");
FC_ASSERT(delim != std::string::npos);
auto pub_key_str = key_spec_pair.substr(0, delim);
auto spec_str = key_spec_pair.substr(delim + 1);
auto spec_delim = spec_str.find(":");
FC_ASSERT(spec_delim != std::string::npos);
auto spec_type_str = spec_str.substr(0, spec_delim);
auto spec_data = spec_str.substr(spec_delim + 1);
auto pubkey = public_key_type(pub_key_str);
if (spec_type_str == "KEY") {
my->_signature_providers[pubkey] = make_key_signature_provider(private_key_type(spec_data));
} else if (spec_type_str == "KEOSD") {
my->_signature_providers[pubkey] = make_keosd_signature_provider(my, spec_data, pubkey);
}
} catch (...) {
elog("Malformed signature provider: \"${val}\", ignoring!", ("val", key_spec_pair));
}
}
}
producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
chain::controller& chain = app().get_plugin<chain_plugin>().chain();
const auto& hbs = chain.head_block_state();
//Schedule for the next second's tick regardless of chain state
// If we would wait less than 50ms (1/10 of block_interval), wait for the whole block interval.
fc::time_point now = fc::time_point::now();
fc::time_point base = std::max<fc::time_point>(now, chain.head_block_time());
int64_t min_time_to_next_block = (config::block_interval_us) - (base.time_since_epoch().count() % (config::block_interval_us) );
fc::time_point block_time = base + fc::microseconds(min_time_to_next_block);
if((block_time - now) < fc::microseconds(config::block_interval_us/10) ) { // we must sleep for at least 50ms
// ilog("Less than ${t}us to next block time, time_to_next_block_time ${bt}",
// ("t", config::block_interval_us/10)("bt", block_time));
block_time += fc::microseconds(config::block_interval_us);
}
_pending_block_mode = pending_block_mode::producing;
// Not our turn
const auto& scheduled_producer = hbs->get_scheduled_producer(block_time);
auto currrent_watermark_itr = _producer_watermarks.find(scheduled_producer.producer_name);
auto signature_provider_itr = _signature_providers.find(scheduled_producer.block_signing_key);
auto irreversible_block_age = get_irreversible_block_age();
// If the next block production opportunity is in the present or future, we're synced.
if( !_production_enabled ) {
_pending_block_mode = pending_block_mode::speculating;
} else if( _producers.find(scheduled_producer.producer_name) == _producers.end()) {
_pending_block_mode = pending_block_mode::speculating;
} else if (signature_provider_itr == _signature_providers.end()) {
elog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key));
_pending_block_mode = pending_block_mode::speculating;
void producer_plugin::plugin_startup()
{ try {
if(fc::get_logger_map().find(logger_name) != fc::get_logger_map().end()) {
_log = fc::get_logger_map()[logger_name];
}
ilog("producer plugin: plugin_startup() begin");
chain::controller& chain = app().get_plugin<chain_plugin>().chain();
my->_accepted_block_connection.emplace(chain.accepted_block.connect( [this]( const auto& bsp ){ my->on_block( bsp ); } ));
my->_irreversible_block_connection.emplace(chain.irreversible_block.connect( [this]( const auto& bsp ){ my->on_irreversible_block( bsp->block ); } ));
const auto lib_num = chain.last_irreversible_block_num();
const auto lib = chain.fetch_block_by_number(lib_num);
if (lib) {
my->on_irreversible_block(lib);
} else {
my->_irreversible_block_time = fc::time_point::maximum();
}
if (!my->_producers.empty()) {
ilog("Launching block production for ${n} producers at ${time}.", ("n", my->_producers.size())("time",fc::time_point::now()));
if (my->_production_enabled) {
if (chain.head_block_num() == 0) {
new_chain_banner(chain);
}
//_production_skip_flags |= eosio::chain::skip_undo_history_check;
}
}
my->schedule_production_loop();
eos_source_dir\libraries\chain\block_header_state.cpp
producer_key block_header_state::get_scheduled_producer( block_timestamp_type t )const {
auto index = t.slot % (active_schedule.producers.size() * config::producer_repetitions);
index /= config::producer_repetitions;
return active_schedule.producers[index];
}
eos_source_dir\libraries\chain\include\eosio\chain\controller.hpp
void initialize_fork_db() {
wlog( " Initializing new blockchain with genesis state " );
producer_schedule_type initial_schedule{ 0, {{N(eosio), conf.genesis.initial_key}} };
class controller {
public:
struct config {
flat_set<account_name> actor_whitelist;
flat_set<account_name> actor_blacklist;
flat_set<account_name> contract_whitelist;
flat_set<account_name> contract_blacklist;
flat_set< pair<account_name, action_name> > action_blacklist;
flat_set<public_key_type> key_blacklist;
path blocks_dir = chain::config::default_blocks_dir_name;
path state_dir = chain::config::default_state_dir_name;
uint64_t state_size = chain::config::default_state_size;
uint64_t reversible_cache_size = chain::config::default_reversible_cache_size;
bool read_only = false;
bool force_all_checks = false;
bool contracts_console = false;
genesis_state genesis;
wasm_interface::vm_type wasm_runtime = chain::config::default_wasm_runtime;
};
eos_source_dir\libraries\chain\genesis_state.cpp
struct genesis_state {
genesis_state();
genesis_state::genesis_state() {
initial_timestamp = fc::time_point::from_iso_string( "2018-06-01T12:00:00" );
initial_key = fc::variant(eosio_root_key).as<public_key_type>();
}
eos_source_dir\CMakeLists.txt
if ("${EOSIO_ROOT_KEY}" STREQUAL "")
set(EOSIO_ROOT_KEY "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV")
endif()
message( STATUS "Using '${EOSIO_ROOT_KEY}' as public key for 'eosio' account" )
结论
对于eosio账户,EOS编译时会从CMakeLists.txt取一个设置的默认公钥作为initial_key缺省值,当nodeos 没有传入--genesis-json
参数时,会走默认参数,但此时并没有EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
公钥的私钥。所以报错。
解决方式有两种
- 编译时修改CMakeLists.txt中
EOSIO_ROOT_KEY
为自己的eosio 公钥 - nodeos运行时传入
--genesis-json 自己的genesis.json路径
对于自己的genesis.json文件中initial_key
修改成与自己的eosio公钥一致
在windows上安装运行EOS
原文地址:https://steemit.com/eos/@tokenika/installing-and-running-eos-on-windows
如果你是一名windows c++开发者,你最喜欢的ide是ms visual studio,那么你可能就想知道能不能直接在windows上编译eos代码。
我们在windows c++编译器上做了几次试验,结果不行。虽然eos的代码有win32的标签,但主要的问题在于,它前后不一致。而且,windows的clang编译器和unix的clang编译器有些不同,它的限制更多。比如,像std::move(u8"env")这样的表达式在windows下是无效的。
不过,我们找到了一个替代的解决办法: Windows Subsystem for Linux,它捆绑了 Visual Studio Code ide。待会你会看到,用这个方法比直接在windows下编译代码更好。
准备工具
你需要 Windows 10, 版本1703, 也就是 Creators Update。想验证你的windows版本,你可以打开设置面板,然后进入系统>关于 进行查看。
如果你用的是更早的版本,而且不想升级到1703版,你仍然可以试一试,不过你要把你的Windows Subsystem for Linux从ubuntu 14 升级到ubuntu 16.
Windows Subsystem for Linux只能安装到系统盘。如果你的系统盘空间不够(Windows Subsystem for Linux需要3-4G的空间),那你可以使用这里的工具拓展你的系统分区。
动手
首先,我们要启动Windows Subsystem for Linux,然后在visual studio里使用bash 命令行界面。
Windows Subsystem for Linux
官方的Windows Subsystem for Linux安装指南在这里可以找到。不过,我们提供了下面的简化版本:
- 在管理员模式下(右击然后选择以管理员运行/Run as Administrator)打开PowerShell,然后执行以下命令:Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
- 按照提示重启计算机。
- 打开开发者模式
- 打开设置面板,进入升级&安全>开发者 页面
- 选择开发者模式Developer Mode单选按钮
- 如果有提示,则重启计算机。
- 打开windows 命令提示器,输入bash。接受证书协议,然后会下载一张用户模式图片,并提取到%localappdata%\lxss\。然后会提示你设置linux用户名和密码。当这步骤结束的时候,快捷名称Bash on Ubuntu on Windows会被加入到你的开始菜单。
- 使用下面任一方式启动一个新的ubuntu shell:
- 在命令提示器内输入bash,或者
- 在开始菜单里使用Bash on Ubuntu on Windows。
- 一旦你进入了linux shell,要确保你运行了ubuntu 16:
lsb_release -a
- 最后,升级 ubuntu:
sudo apt update sudo apt full-upgrade
重装ubuntu
下面的步骤是可选的,不一定非做不可。只有在你需要从头开始,重装ubuntu的时候才需要做。
- 打开windows 命令行提示器,运行:
lxrun /uninstall /full 进行卸载 lxrun /install 进行重装
- 运行bash,启动新的ubuntu shell,然后在这个新的ubuntu shell里进行更新和升级:
sudo apt update sudo apt full-upgrade
Visual Studio Code
从官网下载并安装visual studio code
https://code.visualstudio.com/Download 要想在visual studio code 内启用ubuntu bash 控制台,你需要修改用户设置:
- 进入 File > Preferences > User Settings ,用户>偏好设置>用户设置。
- 在右边面板里添加如下内容,覆盖掉默认设置:"terminal.integrated.shell.windows": "C:\Windows\sysnative\bash.exe".
- 保存修改,你就可以使用Ctrl + ' 或者 View > Integrated Terminal切换到ubuntu 控制台。
你还可以添加c++拓展到visual studio code,这对c++开发有帮助。使用Ctrl + Shift + X打开拓展面板,然后添加以下拓展:
- C/C++
- C++ Intelisense
- CMakeTools
- CMake Tools Helper
- Code Runner
编译源码
在windows文件系统上为EOS创建一个workspace 文件夹。在这篇文章中,我们使用X:\Workspaces\EOS,不过你可以自己决定你想在哪建这个workspace文件夹。
在linux 文件系统中,上面的地址会被映射为/mnt/x/Workspaces/EOS。它会相应地映射你设置的地址。
注意:使用分区名称的小写字母形式,比如我们使用的是/mnt/x/。
到了这一步,你就可以开始使用visual studio code的ubuntu shell了(View > Integrated Terminal)。它的主要优势是它能方便地复制黏贴。
下面的所有命令都是在ubuntu shell上运行的。
- 定义以下系统变量:
export WORKSPACE_DIR=/mnt/x/Workspaces/EOS export EOSIO_INSTALL_DIR=${WORKSPACE_DIR}/eos export EOS_PROGRAMS=${EOSIO_INSTALL_DIR}/build/programs export TEMP_DIR=/tmp
注意:把x/Workspaces/EOS 替换成你设置的workspace地址。
- 把上面设置的系统变量保存到~/.bashrc文件:
echo "export WORKSPACE_DIR=${WORKSPACE_DIR}" >> ~/.bashrc echo "export EOSIO_INSTALL_DIR=${EOSIO_INSTALL_DIR}" >> ~/.bashrc echo "export EOS_PROGRAMS=${EOS_PROGRAMS}" >> ~/.bashrc
- 安装 cmake 和git:
sudo apt install cmake sudo apt install git
4.从EOS代码仓库clone 源代码:
cd ${WORKSPACE_DIR} git clone https://github.com/eosio/eos --recursive
5.现在,你就可以编译源码了。这一步可能需要几个小时时间,取决于你计算机的配置,而且,这期间会要求你确认某些动作,以及输入sudo密码。
cd ${EOSIO_INSTALL_DIR} ./eosio_build.sh
注意:由于这一步需要从多个地方下载文件,它有可能会失败。如果失败的话,就重新开始这一步。
运行
如果以上的步骤没有什么错,你就编译好了EOS代码,它生成了多个文件和可执行文件。可执行文件放在$EOS_PROGRAMS文件夹:
- nodeos: 区块链服务器节点生成组建
- cleos: 和区块链交互的接口命令
- keosd: EOS 钱包
- eosio-launcher:节点网络组成和部署的应用
此贴为转载复制占坑,等稍后 重新整理下。
!wast.empty(): no wast file found eosio.token/eosio.token.wast
今天更新EOS到 release 1.1 重新编译后,发现执行eosio.token合约时提示
surou@surou-C-H110M-K-Pro:~/eos/contracts$ cleos set contract eosio.token eosio.token
Reading WAST/WASM from eosio.token/eosio.token.wast...
1595091ms thread-0 main.cpp:2760 main ] Failed with error: Assert Exception (10)
!wast.empty(): no wast file found eosio.token/eosio.token.wast
查看目录下,确实没有生成 wast文件
surou@surou-C-H110M-K-Pro:~/eos/contracts/eosio.token$ ls
CMakeLists.txt eosio.token.abi eosio.token.cpp eosio.token.hpp
手动编译生成wast
surou@surou-C-H110M-K-Pro:~/eos/contracts/eosio.token$ eosiocpp -o eosio.token.wast eosio.token.cpp
surou@surou-C-H110M-K-Pro:~/eos/contracts/eosio.token$ ls
CMakeLists.txt eosio.token.abi eosio.token.cpp eosio.token.hpp eosio.token.wasm eosio.token.wast
再次部署合约,已经OK
surou@surou-C-H110M-K-Pro:~/eos/contracts$ cleos set contract eosio.token eosio.token
Reading WAST/WASM from eosio.token/eosio.token.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 45460e0ebf7c0bde0a6802adec4dd7bc457c2d4a76f1d97fc6376c88d9db0f28 8032 bytes 1079 us
# eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d01000000017e1560037f7e7f0060057f7e...
# eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e3000030663726561746500020669737375657204...
warning: transaction executed locally, but may not be confirmed by the network yet
也许是编译有什么警告或者异常没注意,或者是EOS更新什么脚本导致的,暂时未做具体跟进,下次更新版本测试后再做补充。