diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index c2a56836d..215903a0c 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -462,6 +462,7 @@ namespace cryptonote crypto::hash prev_id; uint32_t nonce; crypto::signature signature; + uint16_t vote; BEGIN_SERIALIZE() VARINT_FIELD(major_version) @@ -470,7 +471,10 @@ namespace cryptonote FIELD(prev_id) FIELD(nonce) if (major_version >= HF_VERSION_BLOCK_HEADER_MINER_SIG) + { FIELD(signature) + FIELD(vote) + } END_SERIALIZE() }; diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h index eb114c280..69dfb3fe1 100644 --- a/src/cryptonote_basic/cryptonote_boost_serialization.h +++ b/src/cryptonote_basic/cryptonote_boost_serialization.h @@ -199,6 +199,7 @@ namespace boost if (b.major_version >= HF_VERSION_BLOCK_HEADER_MINER_SIG) { a & b.signature; + a & b.vote; } //------------------ a & b.miner_tx; diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index f9b6bf957..a283190b6 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -101,6 +101,7 @@ namespace cryptonote const command_line::arg_descriptor arg_bg_mining_idle_threshold_percentage = {"bg-mining-idle-threshold", "Specify minimum avg idle percentage over lookback interval", miner::BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE, true}; const command_line::arg_descriptor arg_bg_mining_miner_target_percentage = {"bg-mining-miner-target", "Specify maximum percentage cpu use by miner(s)", miner::BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE, true}; const command_line::arg_descriptor arg_spendkey = {"spendkey", "Specify secret spend key used for mining", "", true}; + const command_line::arg_descriptor arg_vote = {"vote", "Vote for proposals.", "", true}; } @@ -294,6 +295,7 @@ namespace cryptonote command_line::add_arg(desc, arg_bg_mining_idle_threshold_percentage); command_line::add_arg(desc, arg_bg_mining_miner_target_percentage); command_line::add_arg(desc, arg_spendkey); + command_line::add_arg(desc, arg_vote); } //----------------------------------------------------------------------------------------------------- bool miner::init(const boost::program_options::variables_map& vm, network_type nettype) @@ -309,6 +311,25 @@ namespace cryptonote m_spendkey = spendkey; m_viewkey = viewkey; } + if(!command_line::has_arg(vm, arg_vote)) + { + m_int_vote = 0; + } else { + m_vote = command_line::get_arg(vm, arg_vote); + if(m_vote != "yes" && m_vote != "no") + { + LOG_ERROR("Voting format error, only a \"yes\" or \"no\" response is accepted"); + return false; + } + if(m_vote == "yes") + { + m_int_vote = 1; + } + if(m_vote == "no") + { + m_int_vote = 2; + } + } if(command_line::has_arg(vm, arg_extra_messages)) { std::string buff; @@ -607,6 +628,7 @@ namespace cryptonote crypto::generate_signature(sig_data, output_public_key, eph_secret_key, signature); // amend signature to block header before PoW hashing b.signature = signature; + b.vote = m_int_vote; } crypto::hash h; @@ -644,6 +666,14 @@ namespace cryptonote " //@@@@@@@@@@@@@@@@@// \n" << ENDL); MGINFO_GREEN("Awesome, you won a block reward!\n" << get_block_hash(b) << " at height " << height); + if (b.vote == 1) + { + MGINFO_GREEN("Your \"YES\" vote has been cast."); + } + if (b.vote == 2) + { + MGINFO_GREEN("Your \"NO\" vote has been cast."); + } cryptonote::block_verification_context bvc; if(!m_phandler->handle_block_found(b, bvc) || !bvc.m_added_to_main_chain) { diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index 79dca4aff..b13f7a1a4 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -138,6 +138,8 @@ namespace cryptonote account_public_address m_mine_address; crypto::secret_key m_spendkey; crypto::secret_key m_viewkey; + std::string m_vote; + uint16_t m_int_vote; epee::math_helper::once_a_time_seconds<5> m_update_block_template_interval; epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; epee::math_helper::once_a_time_seconds<1> m_autodetect_interval; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 30f2f0eec..078192e6e 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1426,6 +1426,11 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, MWARNING("Wrong txout type"); return false; } + if (b.vote > 2) + { + MWARNING("Vote integer must be either 0, 1, or 2"); + return false; + } // keccak hash block header data and check miner signature // if signature is invalid, reject block crypto::hash sig_data = get_sig_data(b); @@ -1438,6 +1443,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, return false; } else { LOG_PRINT_L1("Miner signature is good"); + LOG_PRINT_L1("Vote: " << b.vote); } } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 8b623d504..059dcbd71 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -94,6 +94,7 @@ namespace { void print_block_header(cryptonote::block_header_response const & header) { tools::success_msg_writer() + << "vote: " << header.vote << std::endl << "timestamp: " << boost::lexical_cast(header.timestamp) << " (" << tools::get_human_readable_timestamp(header.timestamp) << ")" << std::endl << "previous hash: " << header.prev_hash << std::endl << "nonce: " << boost::lexical_cast(header.nonce) << std::endl diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index e16695953..e036a21db 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1888,6 +1888,7 @@ namespace cryptonote res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob); res.blockhashing_blob = string_tools::buff_to_hex_nodelimer(hashing_blob); res.status = CORE_RPC_STATUS_OK; + res.vote = 0; return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -2193,6 +2194,7 @@ namespace cryptonote if (b.major_version >= HF_VERSION_BLOCK_HEADER_MINER_SIG) { b.signature = {}; + b.vote = 0; } crypto::hash seed_hash = crypto::null_hash; if (b.major_version >= RX_BLOCK_VERSION && !epee::string_tools::hex_to_pod(template_res.seed_hash, seed_hash)) @@ -2232,6 +2234,7 @@ namespace cryptonote bool core_rpc_server::fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response, bool fill_pow_hash) { PERF_TIMER(fill_block_header_response); + response.vote = blk.vote; response.major_version = blk.major_version; response.minor_version = blk.minor_version; response.timestamp = blk.timestamp; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index bbfd89e38..72f971174 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -924,6 +924,7 @@ namespace cryptonote std::string next_seed_hash; blobdata blocktemplate_blob; blobdata blockhashing_blob; + uint16_t vote; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_PARENT(rpc_response_base) @@ -939,6 +940,7 @@ namespace cryptonote KV_SERIALIZE(blockhashing_blob) KV_SERIALIZE(seed_hash) KV_SERIALIZE(next_seed_hash) + KV_SERIALIZE(vote) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init response; @@ -1132,6 +1134,7 @@ namespace cryptonote std::string pow_hash; uint64_t long_term_weight; std::string miner_tx_hash; + uint16_t vote; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(major_version) @@ -1156,6 +1159,7 @@ namespace cryptonote KV_SERIALIZE(pow_hash) KV_SERIALIZE_OPT(long_term_weight, (uint64_t)0) KV_SERIALIZE(miner_tx_hash) + KV_SERIALIZE(vote) END_KV_SERIALIZE_MAP() }; diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index ae956324c..2acc66bd6 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -898,6 +898,7 @@ namespace rpc if (b.major_version >= HF_VERSION_BLOCK_HEADER_MINER_SIG) { header.signature = b.signature; + header.vote = b.vote; } header.prev_id = b.prev_id; diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h index a2b6fc527..97a148230 100644 --- a/src/rpc/message_data_structs.h +++ b/src/rpc/message_data_structs.h @@ -165,6 +165,7 @@ namespace rpc crypto::hash prev_id; uint32_t nonce; crypto::signature signature; + uint16_t vote; uint64_t height; uint64_t depth; crypto::hash hash; diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index 814991f31..138165696 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -314,6 +314,7 @@ void toJsonValue(rapidjson::Writer& dest, const cryptonote::b INSERT_INTO_JSON_OBJECT(dest, prev_id, b.prev_id); INSERT_INTO_JSON_OBJECT(dest, nonce, b.nonce); INSERT_INTO_JSON_OBJECT(dest, signature, b.signature); + INSERT_INTO_JSON_OBJECT(dest, vote, b.vote); INSERT_INTO_JSON_OBJECT(dest, miner_tx, b.miner_tx); INSERT_INTO_JSON_OBJECT(dest, tx_hashes, b.tx_hashes); @@ -334,6 +335,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b) GET_FROM_JSON_OBJECT(val, b.prev_id, prev_id); GET_FROM_JSON_OBJECT(val, b.nonce, nonce); GET_FROM_JSON_OBJECT(val, b.signature, signature); + GET_FROM_JSON_OBJECT(val, b.vote, vote); GET_FROM_JSON_OBJECT(val, b.miner_tx, miner_tx); GET_FROM_JSON_OBJECT(val, b.tx_hashes, tx_hashes); } @@ -1080,6 +1082,7 @@ void toJsonValue(rapidjson::Writer& dest, const cryptonote::r { dest.StartObject(); + INSERT_INTO_JSON_OBJECT(dest, vote, response.vote); INSERT_INTO_JSON_OBJECT(dest, major_version, response.major_version); INSERT_INTO_JSON_OBJECT(dest, minor_version, response.minor_version); INSERT_INTO_JSON_OBJECT(dest, timestamp, response.timestamp); @@ -1101,6 +1104,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResp throw WRONG_TYPE("json object"); } + GET_FROM_JSON_OBJECT(val, response.vote, vote); GET_FROM_JSON_OBJECT(val, response.major_version, major_version); GET_FROM_JSON_OBJECT(val, response.minor_version, minor_version); GET_FROM_JSON_OBJECT(val, response.timestamp, timestamp); diff --git a/utils/votes.pl b/utils/votes.pl new file mode 100644 index 000000000..8cd37a2d3 --- /dev/null +++ b/utils/votes.pl @@ -0,0 +1,34 @@ +# Script gets votes for a block range. +# Run: perl votes.pl 60 300 + +$IP='127.0.0.1:11181'; + +$begin=$ARGV[0]; +if ($#ARGV == 1 ) { $end=$ARGV[1]; } + +open (F,">vote.txt"); +for ($i=$begin; $i<$end; $i++) { + $k=qq(-d '{"params":{"height":$i},"jsonrpc":"2.0","id":"test","method":"get_block_header_by_height"}' -H 'Content-Type: application/json'); + $k=`curl -s -X POST http://$IP/json_rpc $k`; + $k=~/"vote"\D+(\d+)/sg; + $v=$1; + print F "$v "; +} +close F; + +$s = do{local(@ARGV,$/)="vote.txt";<>}; +$yes = "1"; +$count1 = () = $s =~ /\Q$yes/g; +print "$count1 votes for yes\n"; +$no = "2"; +$count2 = () = $s =~ /\Q$no/g; +print "$count2 votes for no\n"; +$abs = "0"; +$count0 = () = $s =~ /\Q$abs/g; +print "$count0 abstained\n"; + +if ($count1 > $count2) { + print "Computer says... Yes!\n"; +} else { + print "Computer says... No!\n"; +} \ No newline at end of file