提交 ec70cbbf 编写于 作者: M Matt Witherspoon

Merge branch 'eos-noon-net-try2' into eos-noon

......@@ -1126,9 +1126,11 @@ void chain_controller::update_global_dynamic_data(const signed_block& b) {
dgp.recent_slots_filled <<= 1;
dgp.recent_slots_filled += 1;
dgp.recent_slots_filled <<= missed_blocks;
} else {
dgp.recent_slots_filled = 0;
}
} else
if(config::percent_100 * get_global_properties().active_producers.producers.size() / config::blocks_per_round > config::required_producer_participation)
dgp.recent_slots_filled = uint64_t(-1);
else
dgp.recent_slots_filled = 0;
dgp.block_merkle_root.append( head_block_id() );
});
......
......@@ -36,6 +36,8 @@ const static uint32_t fixed_bandwidth_overhead_per_transaction = 100; // 100 byt
const static int percent_100 = 10000;
const static int percent_1 = 100;
const static uint32_t required_producer_participation = 33 * config::percent_1;
static const uint32_t bandwidth_average_window_ms = 24*60*60*1000l;
static const uint32_t compute_average_window_ms = 24*60*60*1000l;
static const uint32_t blocksize_average_window_ms = 60*1000l;
......
......@@ -45,6 +45,10 @@ namespace fc { namespace crypto {
return eq_comparator<signature::storage_type>::apply(p1._storage, p2._storage);
}
bool operator != ( const signature& p1, const signature& p2) {
return !eq_comparator<signature::storage_type>::apply(p1._storage, p2._storage);
}
bool operator < ( const signature& p1, const signature& p2)
{
return less_comparator<signature::storage_type>::apply(p1._storage, p2._storage);
......
digraph G
{
inita->initb [dir="both"]
inita->initc [dir="both"]
inita->initd [dir="both"]
inita->inite [dir="both"]
inita->initf [dir="both"]
inita->initg [dir="both"]
inita->inith [dir="both"]
inita->initi [dir="both"]
inita->initj [dir="both"]
inita->initk [dir="both"]
initb->initc [dir="both"]
initb->initd [dir="both"]
initb->inite [dir="both"]
initb->initf [dir="both"]
initb->initg [dir="both"]
initb->inith [dir="both"]
initb->initi [dir="both"]
initb->initj [dir="both"]
initb->initk [dir="both"]
initc->initd [dir="both"]
initc->inite [dir="both"]
initc->initf [dir="both"]
initc->initg [dir="both"]
initc->inith [dir="both"]
initc->initi [dir="both"]
initc->initj [dir="both"]
initc->initk [dir="both"]
initd->inite [dir="both"]
initd->initf [dir="both"]
initd->initg [dir="both"]
initd->inith [dir="both"]
initd->initi [dir="both"]
initd->initj [dir="both"]
initd->initk [dir="both"]
inite->initf [dir="both"]
inite->initg [dir="both"]
inite->inith [dir="both"]
inite->initi [dir="both"]
inite->initj [dir="both"]
inite->initk [dir="both"]
initf->initg [dir="both"]
initf->inith [dir="both"]
initf->initi [dir="both"]
initf->initj [dir="both"]
initf->initk [dir="both"]
initg->inith [dir="both"]
initg->initi [dir="both"]
initg->initj [dir="both"]
initg->initk [dir="both"]
inith->initi [dir="both"]
inith->initj [dir="both"]
inith->initk [dir="both"]
initi->initj [dir="both"]
initi->initk [dir="both"]
initj->initk [dir="both"]
{
layout="circo";
"testnet_0\nprod=inita,initk,initu"->"testnet_1\nprod=initb,initl" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_2\nprod=initc,initm" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_3\nprod=initd,initn" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_4\nprod=inite,inito" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_2\nprod=initc,initm" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_3\nprod=initd,initn" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_4\nprod=inite,inito" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_3\nprod=initd,initn" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_4\nprod=inite,inito" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_4\nprod=inite,inito" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_5\nprod=initf,initp"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_5\nprod=initf,initp"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_5\nprod=initf,initp"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_5\nprod=initf,initp"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_6\nprod=initg,initq"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_6\nprod=initg,initq"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_6\nprod=initg,initq"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_7\nprod=inith,initr"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_7\nprod=inith,initr"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_8\nprod=initi,inits"->"testnet_9\nprod=initj,initt" [dir="forward"];
}
mesh.png

86.0 KB | W: | H:

mesh.png

294.1 KB | W: | H:

mesh.png
mesh.png
mesh.png
mesh.png
  • 2-up
  • Swipe
  • Onion skin
add_subdirectory(net_plugin)
add_subdirectory(net_api_plugin)
#add_subdirectory(p2p_plugin)
add_subdirectory(http_plugin)
add_subdirectory(chain_plugin)
......
......@@ -98,7 +98,7 @@ namespace eosio {
void http_plugin::set_program_options(options_description&, options_description& cfg) {
cfg.add_options()
("http-server-endpoint", bpo::value<string>()->default_value("127.0.0.1:8888"),
("http-server-address", bpo::value<string>()->default_value("127.0.0.1:8888"),
"The local IP and port to listen for incoming http connections.")
("access-control-allow-origin", bpo::value<string>()->notifier([this](const string& v) {
......@@ -124,15 +124,15 @@ namespace eosio {
}
void http_plugin::plugin_initialize(const variables_map& options) {
if(options.count("http-server-endpoint")) {
if(options.count("http-server-address")) {
#if 0
auto lipstr = options.at("http-server-endpoint").as< string >();
auto lipstr = options.at("http-server-address").as< string >();
auto fcep = fc::ip::endpoint::from_string(lipstr);
my->listen_endpoint = tcp::endpoint(boost::asio::ip::address_v4::from_string((string)fcep.get_address()), fcep.port());
#endif
auto resolver = std::make_shared<tcp::resolver>( std::ref( app().get_io_service() ) );
if( options.count( "http-server-endpoint" ) ) {
auto lipstr = options.at("http-server-endpoint").as< string >();
if( options.count( "http-server-address" ) ) {
auto lipstr = options.at("http-server-address").as< string >();
auto host = lipstr.substr( 0, lipstr.find(':') );
auto port = lipstr.substr( host.size()+1, lipstr.size() );
idump((host)(port));
......
file(GLOB HEADERS "include/eos/net_api_plugin/*.hpp")
add_library( net_api_plugin
net_api_plugin.cpp
${HEADERS} )
target_link_libraries( net_api_plugin net_plugin http_plugin appbase )
target_include_directories( net_api_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
install( TARGETS
net_api_plugin
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
install( FILES ${HEADERS} DESTINATION "include/eos/net_api_plugin" )
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eos/net_plugin/net_plugin.hpp>
#include <eosio/http_plugin/http_plugin.hpp>
#include <appbase/application.hpp>
namespace eosio {
using namespace appbase;
class net_api_plugin : public plugin<net_api_plugin> {
public:
APPBASE_PLUGIN_REQUIRES((net_plugin) (http_plugin))
net_api_plugin() = default;
net_api_plugin(const net_api_plugin&) = delete;
net_api_plugin(net_api_plugin&&) = delete;
net_api_plugin& operator=(const net_api_plugin&) = delete;
net_api_plugin& operator=(net_api_plugin&&) = delete;
virtual ~net_api_plugin() override = default;
virtual void set_program_options(options_description& cli, options_description& cfg) override {}
void plugin_initialize(const variables_map& vm);
void plugin_startup();
void plugin_shutdown() {}
private:
};
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eos/net_api_plugin/net_api_plugin.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/transaction.hpp>
#include <fc/variant.hpp>
#include <fc/io/json.hpp>
#include <chrono>
namespace eosio { namespace detail {
struct net_api_plugin_empty {};
}}
FC_REFLECT(eosio::detail::net_api_plugin_empty, );
namespace eosio {
using namespace eosio;
#define CALL(api_name, api_handle, call_name, INVOKE, http_response_code) \
{std::string("/v1/" #api_name "/" #call_name), \
[&api_handle](string, string body, url_response_callback cb) mutable { \
try { \
if (body.empty()) body = "{}"; \
INVOKE \
cb(http_response_code, fc::json::to_string(result)); \
} catch (fc::eof_exception& e) { \
error_results results{400, "Bad Request", e.to_string()}; \
cb(400, fc::json::to_string(results)); \
elog("Unable to parse arguments: ${args}", ("args", body)); \
} catch (fc::exception& e) { \
error_results results{500, "Internal Service Error", e.to_detail_string()}; \
cb(500, fc::json::to_string(results)); \
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \
} \
}}
#define INVOKE_R_R(api_handle, call_name, in_param) \
auto result = api_handle.call_name(fc::json::from_string(body).as<in_param>());
#define INVOKE_R_R_R_R(api_handle, call_name, in_param0, in_param1, in_param2) \
const auto& vs = fc::json::json::from_string(body).as<fc::variants>(); \
auto result = api_handle.call_name(vs.at(0).as<in_param0>(), vs.at(1).as<in_param1>(), vs.at(2).as<in_param2>());
#define INVOKE_R_V(api_handle, call_name) \
auto result = api_handle.call_name();
#define INVOKE_V_R(api_handle, call_name, in_param) \
api_handle.call_name(fc::json::from_string(body).as<in_param>()); \
eosio::detail::net_api_plugin_empty result;
#define INVOKE_V_R_R(api_handle, call_name, in_param0, in_param1) \
const auto& vs = fc::json::json::from_string(body).as<fc::variants>(); \
api_handle.call_name(vs.at(0).as<in_param0>(), vs.at(1).as<in_param1>()); \
eosio::detail::net_api_plugin_empty result;
#define INVOKE_V_V(api_handle, call_name) \
api_handle.call_name(); \
eosio::detail::net_api_plugin_empty result;
void net_api_plugin::plugin_startup() {
ilog("starting net_api_plugin");
// lifetime of plugin is lifetime of application
auto& net_mgr = app().get_plugin<net_plugin>();
app().get_plugin<http_plugin>().add_api({
// CALL(net, net_mgr, set_timeout,
// INVOKE_V_R(net_mgr, set_timeout, int64_t), 200),
// CALL(net, net_mgr, sign_transaction,
// INVOKE_R_R_R_R(net_mgr, sign_transaction, chain::signed_transaction, flat_set<public_key_type>, chain::chain_id_type), 201),
CALL(net, net_mgr, connect,
INVOKE_R_R(net_mgr, connect, std::string), 201),
CALL(net, net_mgr, disconnect,
INVOKE_R_R(net_mgr, disconnect, std::string), 201),
CALL(net, net_mgr, status,
INVOKE_R_R(net_mgr, status, std::string), 201),
CALL(net, net_mgr, connections,
INVOKE_R_V(net_mgr, connections), 201),
// CALL(net, net_mgr, open,
// INVOKE_V_R(net_mgr, open, std::string), 200),
});
}
void net_api_plugin::plugin_initialize(const variables_map& options) {
if (options.count("http-server-address")) {
const auto& lipstr = options.at("http-server-address").as<string>();
const auto& host = lipstr.substr(0, lipstr.find(':'));
if (host != "localhost" && host != "127.0.0.1") {
wlog("\n"
"*************************************\n"
"* *\n"
"* -- Net API NOT on localhost -- *\n"
"* *\n"
"* this may be abused if exposed *\n"
"* *\n"
"*************************************\n");
}
}
}
#undef INVOKE_R_R
#undef INVOKE_R_R_R_R
#undef INVOKE_R_V
#undef INVOKE_V_R
#undef INVOKE_V_R_R
#undef INVOKE_V_V
#undef CALL
}
......@@ -3,7 +3,7 @@ add_library( net_plugin
net_plugin.cpp
${HEADERS} )
target_link_libraries( net_plugin chain_plugin appbase fc )
target_link_libraries( net_plugin chain_plugin producer_plugin appbase fc )
target_include_directories( net_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
install( TARGETS
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <boost/asio/ip/tcp.hpp>
#include <boost/pool/object_pool.hpp>
#include <fc/io/raw.hpp>
#include <deque>
#include <array>
namespace eosio {
template <uint32_t buffer_len>
class mb_datastream;
/**
* @brief abstraction for a message buffer that spans a chain of physical buffers
*
* This message buffer abstraction will allocate individual character arrays
* of size buffer_len from a boost::object_pool. It supports creation of a
* vector of boost::mutable_buffer for use with async_read() and async_read_some().
* It also supports use with the fc unpack() functionality via a datastream
* helper class.
*/
template <uint32_t buffer_len>
class message_buffer {
public:
/*
* index abstraction that references a point in the chain of buffers.
* first refers to the buffer's index in the deque.
* second refers to the byte in the character buffer.
*/
typedef std::pair<uint32_t, uint32_t> index_t;
message_buffer() : buffers{pool().malloc()}, read_ind{0,0}, write_ind{0,0} { }
~message_buffer() {
while (buffers.size() > 0) {
pool().destroy(buffers.back());
buffers.pop_back();
}
}
/*
* Returns the current read index referencing the byte in the buffer
* that is next to be read.
*/
index_t read_index() const { return read_ind; }
/*
* Returns the current write index referencing the byte in the buffer
* that is next to be written to.
*/
index_t write_index() const { return write_ind; }
/*
* Returns the current read pointer pointing to the memory location
* of the next byte to be read.
*/
char* read_ptr() {
return &buffers[read_ind.first]->at(read_ind.second);
}
/*
* Returns the current write pointer pointing to the memory location
* of the next byte to be written to.
*/
char* write_ptr() {
return &buffers[write_ind.first]->at(write_ind.second);
}
/*
* Adds an additional buffer of buffer_len to the chain of buffers.
* Does not affect the read or write pointer.
*/
void add_buffer_to_chain() {
buffers.push_back(pool().malloc());
}
/*
* Adds additional buffers of length buffer_len to the chain of buffers
* in order to add at least bytes to the space available.
* Does not affect the read or write pointer.
*/
void add_space(uint32_t bytes) {
int buffers_to_add = bytes / buffer_len + 1;
for (int i = 0; i < buffers_to_add; i++) {
buffers.push_back(pool().malloc());
}
}
/*
* Resets the message buffer to the initial state. Any unread data is
* discarded.
*/
void reset() {
read_ind = { 0, 0 };
write_ind = { 0, 0 };
while (buffers.size() > 1) {
pool().destroy(buffers.back());
buffers.pop_back();
}
}
/*
* Returns the current number of bytes remaining to be read.
* Logically, this is the different between where the read and write pointers are.
*/
uint32_t bytes_to_read() const {
return (write_ind.first - read_ind.first) * buffer_len + write_ind.second - read_ind.second;
}
/*
* Returns the current number of bytes available to be written.
* Logically, this is the different between the write pointer and the
* end of the buffer. If this is not enough room, call either
* add_buffer_to_chain() or add_room() to create more space.
*/
uint32_t bytes_to_write() const {
return total_bytes() - write_ind.first * buffer_len - write_ind.second;
}
/*
* Returns the total number of bytes in the buffer chain.
*/
uint32_t total_bytes() const {
return buffer_len * buffers.size();
}
/*
* Advances the read pointer/index the supplied number of bytes along
* the buffer chain. Any buffers that the read pointer moves beyond
* will be removed from the buffer chain. If the read pointer becomes
* equal to the write pointer, the message buffer will be reset to
* its initial state (one buffer with read and write pointers at the
* start).
*/
void advance_read_ptr(uint32_t bytes) {
advance_index(read_ind, bytes);
if (read_ind == write_ind) {
reset();
} else if (read_ind.first > 0) {
while (read_ind.first > 0) {
pool().destroy(buffers.front());
buffers.pop_front();
read_ind.first--;
write_ind.first--;
}
}
}
/*
* Advances the write pointer/index the supplied number of bytes along
* the buffer chain.
*/
void advance_write_ptr(uint32_t bytes) {
advance_index(write_ind, bytes);
while (write_ind.first >= buffers.size()) {
buffers.push_back(pool().malloc());
}
}
/*
* Creates and returns a vector of boost mutable_buffers that can
* be passed to boost async_read() and async_read_some() functions.
* The beginning of the vector will be the write pointer, which
* should be advanced the number of bytes read after the read returns.
*/
std::vector<boost::asio::mutable_buffer> get_buffer_sequence_for_boost_async_read() {
std::vector<boost::asio::mutable_buffer> seq;
FC_ASSERT(write_ind.first < buffers.size());
seq.push_back(boost::asio::buffer(&buffers[write_ind.first]->at(write_ind.second),
buffer_len - write_ind.second));
for (std::size_t i = write_ind.first + 1; i < buffers.size(); i++) {
seq.push_back(boost::asio::buffer(&buffers[i]->at(0), buffer_len));
}
return seq;
}
/*
* Reads size bytes from the buffer chain starting at the read pointer.
* The read pointer is advanced size bytes.
*/
bool read(void* s, uint32_t size) {
if (bytes_to_read() < size) {
return false;
}
if (read_ind.second + size <= buffer_len) {
memcpy(s, read_ptr(), size);
advance_read_ptr(size);
} else {
uint32_t num_in_buffer = buffer_len - read_ind.second;
memcpy(s, read_ptr(), num_in_buffer);
advance_read_ptr(num_in_buffer);
read((char*)s + num_in_buffer, size - num_in_buffer);
}
return true;
}
/*
* Reads size bytes from the buffer chain starting at the supplied index.
* The read pointer is not advanced.
*/
bool peek(void* s, uint32_t size, index_t index) {
if (bytes_to_read() < size) {
return false;
}
if (index.second + size <= buffer_len) {
memcpy(s, get_ptr(index), size);
advance_index(index, size);
} else {
uint32_t num_in_buffer = buffer_len - index.second;
memcpy(s, get_ptr(index), num_in_buffer);
advance_index(index, num_in_buffer);
peek((char*)s + num_in_buffer, size - num_in_buffer, index);
}
return true;
}
/*
* Creates an mb_datastream object that can be used with the
* fc library's unpack functionality.
*/
mb_datastream<buffer_len> create_datastream();
private:
static boost::object_pool<std::array<char, buffer_len> >& pool() {
static boost::object_pool<std::array<char, buffer_len> > pool;
return pool;
}
/*
* Advances the supplied index along the buffer chain the specified
* number of bytes.
*/
static void advance_index(index_t& index, uint32_t bytes) {
index.first += (bytes + index.second) / buffer_len;
index.second = (bytes + index.second) % buffer_len;
}
/*
* Returns the character pointer associated with the supplied index.
*/
char* get_ptr(index_t index) {
return &buffers[index.first]->at(index.second);
}
std::deque<std::array<char, buffer_len>* > buffers;
index_t read_ind;
index_t write_ind;
};
/*
* @brief datastream adapter that adapts message_buffer for use with fc unpack
*
* This class supports unpack functionality but not pack.
*/
// Stream adapter for use with the fc unpack functionality
template <uint32_t buffer_len>
class mb_datastream {
public:
mb_datastream( message_buffer<buffer_len>& m ) : mb(m) {}
inline void skip( size_t s ) { mb.advance_read_ptr(s); }
inline bool read( char* d, size_t s ) {
if (mb.bytes_to_read() >= s) {
mb.read(d, s);
return true;
}
fc::detail::throw_datastream_range_error( "read", mb.bytes_to_read(), s - mb.bytes_to_read());
}
inline bool get( unsigned char& c ) { return mb.read(&c, 1); }
inline bool get( char& c ) { return mb.read(&c, 1); }
private:
message_buffer<buffer_len>& mb;
};
template <uint32_t buffer_len>
inline mb_datastream<buffer_len> message_buffer<buffer_len>::create_datastream() {
return mb_datastream<buffer_len>(*this);
}
} // namespace eosio
......@@ -5,10 +5,18 @@
#pragma once
#include <appbase/application.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eos/net_plugin/protocol.hpp>
namespace eosio {
using namespace appbase;
struct connection_status {
string peer;
bool connecting = false;
bool syncing = false;
handshake_message last_handshake;
};
class net_plugin : public appbase::plugin<net_plugin>
{
public:
......@@ -22,10 +30,18 @@ namespace eosio {
void plugin_startup();
void plugin_shutdown();
void broadcast_block(const chain::signed_block &sb);
void broadcast_block(const chain::signed_block &sb);
string connect( const string& endpoint );
string disconnect( const string& endpoint );
optional<connection_status> status( const string& endpoint )const;
vector<connection_status> connections()const;
size_t num_peers() const;
private:
std::unique_ptr<class net_plugin_impl> my;
};
}
FC_REFLECT( eosio::connection_status, (peer)(connecting)(syncing)(last_handshake) )
......@@ -5,24 +5,32 @@
#pragma once
#include <eosio/chain/block.hpp>
#include <eosio/chain/types.hpp>
#include <eos/net_plugin/protocol.hpp>
#include <chrono>
namespace eosio {
using namespace chain;
using namespace fc;
struct handshake_message {
int16_t network_version = 0; ///< derived from git commit hash, not sequential
chain_id_type chain_id; ///< used to identify chain
fc::sha256 node_id; ///< used to identify peers and prevent self-connect
string p2p_address;
uint32_t last_irreversible_block_num = 0;
block_id_type last_irreversible_block_id;
uint32_t head_num = 0;
block_id_type head_id;
string os;
string agent;
int16_t generation;
static_assert(sizeof(std::chrono::system_clock::duration::rep) >= 8, "system_clock is expected to be at least 64 bits");
typedef std::chrono::system_clock::duration::rep tstamp;
struct handshake_message {
int16_t network_version = 0; ///< derived from git commit hash, not sequential
chain_id_type chain_id; ///< used to identify chain
fc::sha256 node_id; ///< used to identify peers and prevent self-connect
chain::public_key_type key; ///< authentication key; may be a producer or peer key, or empty
tstamp time;
fc::sha256 token; ///< digest of time to prove we own the private key of the key above
chain::signature_type sig; ///< signature for the digest
string p2p_address;
uint32_t last_irreversible_block_num = 0;
block_id_type last_irreversible_block_id;
uint32_t head_num = 0;
block_id_type head_id;
string os;
string agent;
int16_t generation;
};
enum go_away_reason {
......@@ -36,7 +44,7 @@ namespace eosio {
bad_transaction ///< the peer sent a transaction that failed verification
};
const string reason_str( go_away_reason rsn ) {
constexpr auto reason_str( go_away_reason rsn ) {
switch (rsn ) {
case no_reason : return "no reason";
case self : return "self connect";
......@@ -71,13 +79,15 @@ namespace eosio {
enum id_list_modes {
none,
catch_up,
last_irr_catch_up,
normal
};
const string modes_str( id_list_modes m ) {
constexpr auto modes_str( id_list_modes m ) {
switch( m ) {
case none : return "none";
case catch_up : return "catch up";
case last_irr_catch_up : return "last irreversible";
case normal : return "normal";
default: return "undefined mode";
}
......@@ -104,7 +114,7 @@ namespace eosio {
ordered_blk_ids req_blocks;
};
#if 0
#if 0 //disabling block summary support
struct processed_trans_summary {
transaction_id_type id;
vector<message_output> outmsgs;
......@@ -114,11 +124,12 @@ namespace eosio {
vector<transaction_id_type> gen_trx; // is this necessary to send?
vector<processed_trans_summary> user_trx;
};
using cycle_ids = vector<thread_ids>;
#endif
#endif
struct block_summary_message {
signed_block_header block_header;
#if 0
#if 0 //disabling block summary support
vector<cycle_ids> trx_ids;
#endif
};
......@@ -142,14 +153,14 @@ namespace eosio {
FC_REFLECT( eosio::select_ids<fc::sha256>, (mode)(pending)(ids) )
FC_REFLECT( eosio::handshake_message,
(network_version)(chain_id)(node_id)
(p2p_address)
(network_version)(chain_id)(node_id)(key)
(time)(token)(sig)(p2p_address)
(last_irreversible_block_num)(last_irreversible_block_id)
(head_num)(head_id)
(os)(agent)(generation) )
FC_REFLECT( eosio::go_away_message, (reason)(node_id) )
FC_REFLECT( eosio::time_message, (org)(rec)(xmt)(dst) )
#if 0
#if 0 //disabling block summary support
FC_REFLECT( eosio::processed_trans_summary, (id)(outmsgs) )
FC_REFLECT( eosio::thread_ids, (gen_trx)(user_trx) )
#endif
......
此差异已折叠。
......@@ -5,7 +5,7 @@ add_library( producer_plugin
${HEADERS}
)
target_link_libraries( producer_plugin chain_plugin appbase eosio_chain eos_utilities )
target_link_libraries( producer_plugin chain_plugin appbase eosio_chain eos_utilities net_plugin )
target_include_directories( producer_plugin
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
......
......@@ -38,6 +38,10 @@ public:
boost::program_options::options_description &config_file_options
) override;
chain::public_key_type first_producer_public_key() const;
bool is_producer_key(const chain::public_key_type& key) const;
chain::signature_type sign_compact(const chain::public_key_type& key, const fc::sha256& digest) const;
virtual void plugin_initialize(const boost::program_options::variables_map& options);
virtual void plugin_startup();
virtual void plugin_shutdown();
......
......@@ -3,7 +3,7 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/producer_plugin/producer_plugin.hpp>
#include <eos/net_plugin/net_plugin.hpp>
#include <eosio/chain/producer_object.hpp>
#include <fc/io/json.hpp>
......@@ -32,7 +32,7 @@ public:
boost::program_options::variables_map _options;
bool _production_enabled = false;
uint32_t _required_producer_participation = 33 * chain::config::percent_1;
uint32_t _required_producer_participation = uint32_t(config::required_producer_participation);
uint32_t _production_skip_flags = eosio::chain::skip_nothing;
std::map<chain::public_key_type, chain::private_key_type> _private_keys;
......@@ -82,11 +82,42 @@ void producer_plugin::set_program_options(
("ID of producer controlled by this node (e.g. inita; may specify multiple times)"))
("private-key", boost::program_options::value<vector<string>>()->composing()->multitoken()->default_value({fc::json::to_string(private_key_default)},
fc::json::to_string(private_key_default)),
"Tuple of [public_key, WIF private key] (may specify multiple times)")
"Tuple of [public key, WIF private key] (may specify multiple times)")
;
config_file_options.add(producer_options);
}
chain::public_key_type producer_plugin::first_producer_public_key() const
{
chain::chain_controller& chain = app().get_plugin<chain_plugin>().chain();
try {
return chain.get_producer(*my->_producers.begin()).signing_key;
} catch(std::out_of_range) {
return chain::public_key_type();
}
}
bool producer_plugin::is_producer_key(const chain::public_key_type& key) const
{
auto private_key_itr = my->_private_keys.find(key);
if(private_key_itr != my->_private_keys.end())
return true;
return false;
}
chain::signature_type producer_plugin::sign_compact(const chain::public_key_type& key, const fc::sha256& digest) const
{
if(key != chain::public_key_type()) {
auto private_key_itr = my->_private_keys.find(key);
FC_ASSERT(private_key_itr != my->_private_keys.end(), "Local producer has no private key in config.ini corresponding to public key ${key}", ("key", key));
return private_key_itr->second.sign(digest);
}
else {
return chain::signature_type();
}
}
template<typename T>
T dejsonify(const string& s) {
return fc::json::from_string(s).as<T>();
......@@ -289,7 +320,8 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
capture("n", block.block_num())("t", block.timestamp)("c", now)("count",block.input_transactions.size())("id",string(block.id()).substr(8,8));
app().get_plugin<net_plugin>().broadcast_block(block);
return block_production_condition::produced;
}
} // namespace eos
} // namespace eosio
......@@ -97,8 +97,8 @@ void wallet_api_plugin::plugin_startup() {
}
void wallet_api_plugin::plugin_initialize(const variables_map& options) {
if (options.count("http-server-endpoint")) {
const auto& lipstr = options.at("http-server-endpoint").as<string>();
if (options.count("http-server-address")) {
const auto& lipstr = options.at("http-server-address").as<string>();
const auto& host = lipstr.substr(0, lipstr.find(':'));
if (host != "localhost" && host != "127.0.0.1") {
wlog("\n"
......
......@@ -143,6 +143,13 @@ const string get_transactions_func = account_history_func_base + "/get_transacti
const string get_key_accounts_func = account_history_func_base + "/get_key_accounts";
const string get_controlled_accounts_func = account_history_func_base + "/get_controlled_accounts";
const string net_func_base = "/v1/net";
const string net_connect = net_func_base + "/connect";
const string net_disconnect = net_func_base + "/disconnect";
const string net_status = net_func_base + "/status";
const string net_connections = net_func_base + "/connections";
const string wallet_func_base = "/v1/wallet";
const string wallet_create = wallet_func_base + "/create";
const string wallet_open = wallet_func_base + "/open";
......@@ -809,6 +816,38 @@ int main( int argc, char** argv ) {
std::cout << fc::json::to_pretty_string( call( push_txn_func, trx )) << std::endl;
});
// Net subcommand
string new_host;
auto net = app.add_subcommand( "net", localized("Interact with local p2p network connections"), false );
net->require_subcommand();
auto connect = net->add_subcommand("connect", localized("start a new connection to a peer"), false);
connect->add_option("host", new_host, localized("The hostname:port to connect to."))->required();
connect->set_callback([&] {
const auto& v = call(host, port, net_connect, new_host);
std::cout << fc::json::to_pretty_string(v) << std::endl;
});
auto disconnect = net->add_subcommand("disconnect", localized("close an existing connection"), false);
disconnect->add_option("host", new_host, localized("The hostname:port to disconnect from."))->required();
disconnect->set_callback([&] {
const auto& v = call(host, port, net_disconnect, new_host);
std::cout << fc::json::to_pretty_string(v) << std::endl;
});
auto status = net->add_subcommand("status", localized("status of existing connection"), false);
status->add_option("host", new_host, localized("The hostname:port to query status of connection"))->required();
status->set_callback([&] {
const auto& v = call(host, port, net_status, new_host);
std::cout << fc::json::to_pretty_string(v) << std::endl;
});
auto connections = net->add_subcommand("peers", localized("status of all existing peers"), false);
connections->set_callback([&] {
const auto& v = call(host, port, net_connections, new_host);
std::cout << fc::json::to_pretty_string(v) << std::endl;
});
// Wallet subcommand
auto wallet = app.add_subcommand( "wallet", localized("Interact with local wallet"), false );
......
......@@ -33,7 +33,7 @@ target_link_libraries( eosiod
# PRIVATE account_history_api_plugin account_history_plugin db_plugin
PRIVATE chain_api_plugin producer_plugin chain_plugin
PRIVATE wallet_api_plugin
PRIVATE net_plugin
PRIVATE net_plugin net_api_plugin
PRIVATE http_plugin
PRIVATE eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
......
......@@ -8,7 +8,8 @@
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eosio/http_plugin/http_plugin.hpp>
#include <eosio/chain_api_plugin/chain_api_plugin.hpp>
#include <eosio/net_plugin/net_plugin.hpp>
#include <eos/net_plugin/net_plugin.hpp>
#include <eos/net_api_plugin/net_api_plugin.hpp>
//#include <eosio/account_history_plugin/account_history_plugin.hpp>
//#include <eosio/account_history_api_plugin/account_history_api_plugin.hpp>
#include <eosio/wallet_api_plugin/wallet_api_plugin.hpp>
......@@ -31,8 +32,9 @@ int main(int argc, char** argv)
app().register_plugin<chain_api_plugin>();
app().register_plugin<producer_plugin>();
// app().register_plugin<account_history_api_plugin>();
app().register_plugin<wallet_api_plugin>();
app().register_plugin<net_plugin>();
app().register_plugin<net_api_plugin>();
app().register_plugin<wallet_api_plugin>();
if(!app().initialize<chain_plugin, http_plugin>(argc, argv))
return -1;
app().startup();
......
此差异已折叠。
digraph G
{
inita->initb [dir="both"]
inita->initd [dir="both"]
inita->initf [dir="both"]
inita->inith [dir="both"]
inita->initj [dir="both"]
initb->initc [dir="both"]
initb->inite [dir="both"]
initb->initg [dir="both"]
initb->initi [dir="both"]
initb->initk [dir="both"]
initc->initd [dir="both"]
initc->initf [dir="both"]
initc->inith [dir="both"]
initc->initj [dir="both"]
initd->inite [dir="both"]
initd->initg [dir="both"]
initd->initi [dir="both"]
initd->initk [dir="both"]
inite->initf [dir="both"]
inite->inith [dir="both"]
inite->initj [dir="both"]
initf->initg [dir="both"]
initf->initi [dir="both"]
initf->initk [dir="both"]
initg->inith [dir="both"]
initg->initj [dir="both"]
inith->initi [dir="both"]
inith->initk [dir="both"]
initi->initj [dir="both"]
initi->initk [dir="both"]
initj->initk [dir="both"]
{
layout="circo";
"testnet_0\nprod=inita,initk,initu"->"testnet_3\nprod=initd,initn" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_0\nprod=inita,initk,initu"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_4\nprod=inite,inito" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_1\nprod=initb,initl"->"testnet_0\nprod=inita,initk,initu" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_2\nprod=initc,initm"->"testnet_1\nprod=initb,initl" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_3\nprod=initd,initn"->"testnet_2\nprod=initc,initm" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_0\nprod=inita,initk,initu" [dir="forward"];
"testnet_4\nprod=inite,inito"->"testnet_3\nprod=initd,initn" [dir="forward"];
"testnet_5\nprod=initf,initp"->"testnet_8\nprod=initi,inits" [dir="forward"];
"testnet_5\nprod=initf,initp"->"testnet_1\nprod=initb,initl" [dir="forward"];
"testnet_5\nprod=initf,initp"->"testnet_4\nprod=inite,inito" [dir="forward"];
"testnet_6\nprod=initg,initq"->"testnet_9\nprod=initj,initt" [dir="forward"];
"testnet_6\nprod=initg,initq"->"testnet_2\nprod=initc,initm" [dir="forward"];
"testnet_6\nprod=initg,initq"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_7\nprod=inith,initr"->"testnet_0\nprod=inita,initk,initu" [dir="forward"];
"testnet_7\nprod=inith,initr"->"testnet_3\nprod=initd,initn" [dir="forward"];
"testnet_7\nprod=inith,initr"->"testnet_6\nprod=initg,initq" [dir="forward"];
"testnet_8\nprod=initi,inits"->"testnet_1\nprod=initb,initl" [dir="forward"];
"testnet_8\nprod=initi,inits"->"testnet_4\nprod=inite,inito" [dir="forward"];
"testnet_8\nprod=initi,inits"->"testnet_7\nprod=inith,initr" [dir="forward"];
"testnet_9\nprod=initj,initt"->"testnet_2\nprod=initc,initm" [dir="forward"];
"testnet_9\nprod=initj,initt"->"testnet_5\nprod=initf,initp" [dir="forward"];
"testnet_9\nprod=initj,initt"->"testnet_8\nprod=initi,inits" [dir="forward"];
}
star.png

117.9 KB | W: | H:

star.png

225.4 KB | W: | H:

star.png
star.png
star.png
star.png
  • 2-up
  • Swipe
  • Onion skin
[toc]
#EOS Testnet
# EOS Testnet
To date, all work done to experiment with the EOS blockchain has been performed using a single instance of eosd hosting all 21 block producers. While this is a perfectly valid solution for validating features of the blockchain, developing new contracts, or whatever, it does not scale. Nor does it expose the sort of issues raised when contract and block data must be shared across multiple instances. Providing the ability to scale involves deploying multiple eosd nodes across many hosts and lining then into a peer-to-peer (p2p) network. Composing this network involves tailoring and distributing configuration files, coordinating starts and stops and other tasks.
Doing this manually is a tedious task and easily error prone. Fortunately a solution is provided, in the form of the Launcher application, described below.
......@@ -31,28 +29,28 @@ Note that the Launcher will not push instances of eosd to the remote hosts, you
### Network Topology
Network topology or "shape" describes how the nodes are connected in order to share transaction and block data, and requests for the same. The idea for varying network topology is that there is a trade off between the number of times a node must send a message reporting a new transaction or block, vs the number of times that message must be repeated to ensure all nodes know of it.
The Launcher has definitions of three different network "shapes" based on inter-nodal connections, which can be selected by a command line option, or you can supply your own network topology by editing the Launcher generated configuration file.
####Ring network
![](ring.png "Ring Diagram")
This is the simplest network, where each node identifies just the node next to it as it's only peer.
The Launcher has definitions of two basic different network "shapes" based on inter-nodal connections, which can be selected by a command line option. If you wish to create your own custom network topology, you can do so by supplying a json formatted file. This file is typically the edited version of the template created by the launcher in "output" mode.
####Star network
![](star.png "Star Diagram")
#### Star network
![](https://github.com/EOSIO/eos/raw/master/star.png)
A "star" is intended to support a larger number of nodes in the testnet. In this case the number of peers connected to a node and the distribution of those nodes varies based on the number of nodes in the network.
####Mesh network
![](mesh.png "Mesh Diagram")
#### Mesh network
![](https://github.com/EOSIO/eos/raw/master/mesh.png)
In a "mesh" network, each node is connected to as many peer nodes as possible.
#The Launcher Application
#### Custom network shape
![](custom.png)
This is an example of a custom deployment where clusters of nodes are isolated except through a single crosslink.
# The Launcher Application
To address the complexity implied by distributing multiple eosd nodes across a LAN or a wider network, the launcher application was created.
Based on a handful of command line arguments the Launcher is able to compose per-node configuration files, distribute these files securely amongst the peer hosts, then start up the multiple instances of eosd.
Eosd instances started this way have their output logged in individual text files. Finally the launcher application is also able to shut down some or all of the test network.
##Running the Launcher application
## Running the Launcher application
The launcher program is used to configure and deploy producing and non-producing eosd nodes that talk to each other using configured routes. The configuration for each node is stored in separate directories, permitting multiple nodes to be active on the same host, assuming the machine has sufficient memory and disk space for multiple eosd instances. The launcher makes use of multiple configuration sources in order to deploy a testnet. A handful of command line arguments can be used to set up simple local networks.
......@@ -65,11 +63,12 @@ For the moment the launcher only activates platform-native nodes, dockerized nod
Here is the current list of command line arguments recognized by the launcher.
```
Testnet launcher options:
launcher command line arguments:
-n [ --nodes ] arg (=1) total number of nodes to configure and
launch
-p [ --pnodes ] arg (=1) number of nodes that are producers
-s [ --shape ] arg (=ring) network topology, use "ring" "star"
-d [ --delay ] arg (=0) number of seconds to wait before starting the next node. Used to simulate a person keying in a series of individual eosd startup command lines.
-s [ --shape ] arg (=star) network topology, use "star"
"mesh" or give a filename for custom
-g [ --genesis ] arg (="./genesis.json")
set the path to genesis.json
......@@ -77,22 +76,27 @@ Testnet launcher options:
in this file
--skip-signature EOSD does not require transaction
signatures.
-i [ --timestamp ] arg set the timestamp for the first block.
-i [ --timestamp ] arg set the timestamp for the first block.
Use "now" to indicate the current time
-l [ --launch ] arg select a subset of nodes to launch.
Currently may be "all", "none", or
"local". If not set, the default is to
launch all unless an output file is
named, in which case it starts none.
-k [ --kill ] The launcher retrieves the previously
started process ids and issue a sigterm
to each.
-k [ --kill ] arg The launcher retrieves the previously
started process ids and signals each with the specified signum. Use 15 for a sigterm and 9 for sigkill.
-h [ --help ] print this list
```
Note that if a testnet.json file is supplied as the `--shape` argument, then the `--nodes`, `--pnodes`, and `--genesis` arguments are all ignored.
## The testnet.json Configuration File
This is the file generated by running the launcher with the `--output` argument. The object described in this file is composed of a helper for using ssl, and a collection of testnet node descriptors. The node descriptors are listed as name, value pairs. Note that the names serve a dual purpose acting as both the key in a map of node descriptors and as an alias for the node in the peer lists. For example:
## The Generated Multihost Testnet Configuration File
This is the file generated by running the following command:
`launcher --output <filename> [other options]`
In this mode, the launcher does not activate any eosd instances, it produces a file of the given filename. This file is a JSON formatted template that provides an easy means of
The object described in this file is composed of a helper for using ssl, and a collection of testnet node descriptors. The node descriptors are listed as name, value pairs. Note that the names serve a dual purpose acting as both the key in a map of node descriptors and as an alias for the node in the peer lists. For example:
```
{
......@@ -145,39 +149,39 @@ The ssh helper fields are paths to ssh and scp, an identity if necessary, and an
The rest of the testnet.json file is the collection of node descriptors. The fragment shown above was created with the command line `programs/launcher/launcher -p6 -s mesh -o testnet.json` and then edited to refer to a remote host named "remoteserv."
###Elements Of The JSON File
### Elements Of The JSON File
This table describes all of the key/value pairs used in the testnet.json file.
|Value | Description
|:------------- | :-----------
|ssh_helper | a set of values used to facilitate the use of SSH and SCP
nodes | a collection of descriptors defining the eosd instances used to assemble this testnet. The names used as keys in this collection are also aliases used within as placeholders for peer nodes.
|Value | Description
| :------------ | :-----------
| ssh_helper | a set of values used to facilitate the use of SSH and SCP
| nodes | a collection of descriptors defining the eosd instances used to assemble this testnet. The names used as keys in this collection are also aliases used within as placeholders for peer nodes.
|ssh_helper elements | Description
|:---------- | :------------
ssh_cmd | path to the local ssh command
scp_cmd | path to the local scp command
ssh_args | any additional command line arguments needed to successfully connect to remote peers
ssh_identity | The user name to use when accessing the remote hosts
|per-node elements | Description
|:-------- | :----------
genesis | path to the genesis.json file. This should be the same file for all members of the testnet.
remote | specifies whether this node is in the local network or not. This flag ties in with the launch mode command line option (-l) to determine if the local launcher instance will attempt to start this node.
ssh_identity | a per-node override of the general ssh_identity defined above.
ssh_args | a per-node override of the general ssh_args
eos_root_dir | specifies the directory into which all eosd artifacts are based. This is required for any hosts that are not the local host.
data_dir | the root for the remaining node-specific settings below.
hostname | the domain name for the server, or its IP address.
public_name | possibly different from the hostname, this name will get substituted for the aliases when creating the per-node config.ini file's peer list.
p2p_port | combined with the public name to identify the endpoint listed on for peer connections. When multiple nodes share a host, the p2p_port is automatically incremented for each node.
http_port | defines the listen endpoint for the client API services
filesize | sets the capacity in megabytes for the size of the blockchain backing store file.
keys | specify the authentication tokens for this node.
peers | this list indicates the other nodes in the network to which this one actively connects. Since this file may be edited to alter the hostname, public name, or p2p port values, the peers list here holds aliases for the actual endpoints eventually written to the individual config.ini files.
producers | this list identifies which of the producers from the genesis.json file are held by this node. Note that the launcher uses a round-robin algorithm to spread the producer instances across the producing nodes.
###Provisioning Distributed Servers
| :---------- | :------------
| ssh_cmd | path to the local ssh command
| scp_cmd | path to the local scp command
| ssh_args | any additional command line arguments needed to successfully connect to remote peers
| ssh_identity | The user name to use when accessing the remote hosts
|node elements | Description
| :-------- | :----------
| genesis | path to the genesis.json file. This should be the same file for all members of the testnet.
| remote | specifies whether this node is in the local network or not. This flag ties in with the launch mode command line option (-l) to determine if the local launcher instance will attempt to start this node.
| ssh_identity | a per-node override of the general ssh_identity defined above.
| ssh_args | a per-node override of the general ssh_args
| eos_root_dir | specifies the directory into which all eosd artifacts are based. This is required for any hosts that are not the local host.
| data_dir | the root for the remaining node-specific settings below.
| hostname | the domain name for the server, or its IP address.
| public_name | possibly different from the hostname, this name will get substituted for the aliases when creating the per-node config.ini file's peer list.
| p2p_port | combined with the public name to identify the endpoint listed on for peer connections. When multiple nodes share a host, the p2p_port is automatically incremented for each node.
| http_port | defines the listen endpoint for the client API services
| filesize | sets the capacity in megabytes for the size of the blockchain backing store file.
| keys | specify the authentication tokens for this node.
| peers | this list indicates the other nodes in the network to which this one actively connects. Since this file may be edited to alter the hostname, public name, or p2p port values, the peers list here holds aliases for the actual endpoints eventually written to the individual config.ini files.
| producers | this list identifies which of the producers from the genesis.json file are held by this node. Note that the launcher uses a round-robin algorithm to spread the producer instances across the producing nodes.
### Provisioning Distributed Servers
The ssh_helper section of the testnet.json file contains the ssh elements necessary to connect and issue commands to other servers. In addition to the ssh_helper section which provides access to global configuration settings, the per-node configuration may provide overriding identity and connection arguments.
It is also necessary to provision the server by at least copying the eosd executable, and the genesis.json files to their appropriate locations relative to some named EOS root directory. For example, I defined the EOS root to be `/home/phil/blockchain/eos`. When run, the launcher will run through a variety of shell commands using ssh and finally using scp to copy a config.ini file to the appropriate data directory on the remote.
......@@ -187,17 +191,11 @@ The launcher app creates a separate date and configuration directory for each no
| Per-Node File | Description
| :------------ | :----------
| config.ini | The eosd configuration file.
| eosd.pid | The process ID of the running eosd instance.
| blockchain/* | The blockchain backing store
| blocks/* | The blockchain log store
| stderr.txt | The cerr output from eosd.
| stdout.txt | The cout output from eosd.
A file called "last_run.json" contains hints for a later instance of the launcher to be able to kill local and remote nodes when run with -k.
#What Remains To Be Done
Functionality that remains to be implemented: caching signed transactions then purging them on a schedule. Sending summaries of blocks rather than whole blocks. Optimizing the routing between nodes. Failover during new node synchronization if a peer fails to respond timely enough
Also need to prepare tests that are distributed, deterministic, and repeatable.
| config.ini | The eosd configuration file.
| eosd.pid | The process ID of the running eosd instance.
| blockchain/* | The blockchain backing store
| blocks/* | The blockchain log store
| stderr.txt | The cerr output from eosd.
| stdout.txt | The cout output from eosd.
A file called "last_run.json" contains hints for a later instance of the launcher to be able to kill local and remote nodes when run with -k 15.
......@@ -93,7 +93,7 @@ LOG_FILE=eosd_run_test.log
programs/launcher/launcher --eosd "--plugin eosio::db_plugin --mongodb-uri $DB"
verifyErrorCode "launcher"
sleep 60
count=`grep -c "generated block" tn_data_0/stderr.txt`
count=`grep -c "generated block" tn_data_00/stderr.txt`
if [[ $count == 0 ]]; then
error "FAILURE - no blocks produced"
fi
......@@ -461,10 +461,10 @@ while [ "$NEXT_BLOCK_NUM" -le "$HEAD_BLOCK_NUM" ]; do
NEXT_BLOCK_NUM=$((NEXT_BLOCK_NUM+1))
done
ASSERT_ERRORS="$(grep Assert tn_data_0/stderr.txt)"
count=`grep -c Assert tn_data_0/stderr.txt`
ASSERT_ERRORS="$(grep Assert tn_data_00/stderr.txt)"
count=`grep -c Assert tn_data_00/stderr.txt`
if [ $count != 0 ]; then
error "FAILURE - Assert in tn_data_0/stderr.txt"
error "FAILURE - Assert in tn_data_00/stderr.txt"
fi
killAll
......
......@@ -39,11 +39,11 @@ error()
(>&2 echo $1)
killAll
echo =================================================================
echo Contents of tn_data_0/config.ini:
cat tn_data_0/config.ini
echo Contents of tn_data_00/config.ini:
cat tn_data_00/config.ini
echo =================================================================
echo Contents of tn_data_0/stderr.txt:
cat tn_data_0/stderr.txt
echo Contents of tn_data_00/stderr.txt:
cat tn_data_00/stderr.txt
echo =================================================================
echo Contents of test_walletd_output.log:
cat test_walletd_output.log
......@@ -121,7 +121,7 @@ if [ "$SERVER" == "localhost" ]; then
programs/launcher/launcher
verifyErrorCode "launcher"
sleep 7
count=`grep -c "generated block" tn_data_0/stderr.txt`
count=`grep -c "generated block" tn_data_00/stderr.txt`
if [[ $count == 0 ]]; then
error "FAILURE - no blocks produced"
fi
......@@ -153,7 +153,7 @@ fi
#
# walletd
programs/eos-walletd/eos-walletd --data-dir test_wallet_0 --http-server-endpoint=127.0.0.1:8899 > test_walletd_output.log 2>&1 &
programs/eos-walletd/eos-walletd --data-dir test_wallet_0 --http-server-address=127.0.0.1:8899 > test_walletd_output.log 2>&1 &
verifyErrorCode "eos-walletd"
WALLETD_PROC_ID=$!
sleep 3
......@@ -491,14 +491,15 @@ while [ "$NEXT_BLOCK_NUM" -le "$HEAD_BLOCK_NUM" ]; do
NEXT_BLOCK_NUM=$((NEXT_BLOCK_NUM+1))
done
ASSERT_ERRORS="$(grep Assert tn_data_0/stderr.txt)"
count=`grep -c Assert tn_data_0/stderr.txt`
if [ $count != 0 ]; then
error "FAILURE - Assert in tn_data_0/stderr.txt"
if [ "$SERVER" == "localhost" ]; then
ASSERT_ERRORS="$(grep Assert tn_data_00/stderr.txt)"
count=`grep -c Assert tn_data_00/stderr.txt`
if [ "$count" != "0" ]; then
error "FAILURE - Assert in tn_data_00/stderr.txt"
fi
fi
killAll
cleanup
echo "END" >> $TEST_OUTPUT
echo SUCCESS!
......@@ -102,11 +102,11 @@ sub write_config {
print $cfg "readonly = 0\n";
print $cfg "shared-file-dir = blockchain\n";
print $cfg "shared-file-size = 64\n";
print $cfg "http-server-endpoint = 127.0.0.1:$http_port[$i]\n";
print $cfg "listen-endpoint = 0.0.0.0:$p2p_port[$i]\n";
print $cfg "public-endpoint = $hostname:$p2p_port[$i]\n";
print $cfg "http-server-address = 127.0.0.1:$http_port[$i]\n";
print $cfg "p2p-listen-endpoint = 0.0.0.0:$p2p_port[$i]\n";
print $cfg "p2p-server-address = $hostname:$p2p_port[$i]\n";
foreach my $peer (@peers) {
print $cfg "remote-endpoint = $peer\n";
print $cfg "p2p-peer-address = $peer\n";
}
if (defined $producer) {
......
......@@ -46,7 +46,12 @@ fi
total_nodes="${total_nodes:-`echo $pnodes`}"
rm -rf tn_data_*
programs/launcher/launcher -p $pnodes -n $total_nodes -s $topo -d $delay
if [ "$delay" == 0 ]; then
programs/launcher/launcher -p $pnodes -n $total_nodes -s $topo
else
programs/launcher/launcher -p $pnodes -n $total_nodes -s $topo -d $delay
fi
sleep 7
echo "start" > test.out
port=8888
......@@ -94,9 +99,9 @@ fi
echo ERROR: $lines reports out of $total_nodes and prods = $prodsfound
programs/launcher/launcher -k 15
echo =================================================================
echo Contents of tn_data_0/config.ini:
cat tn_data_0/config.ini
echo Contents of tn_data_00/config.ini:
cat tn_data_00/config.ini
echo =================================================================
echo Contents of tn_data_0/stderr.txt:
cat tn_data_0/stderr.txt
echo Contents of tn_data_00/stderr.txt:
cat tn_data_00/stderr.txt
exit 1
......@@ -414,9 +414,9 @@ BOOST_FIXTURE_TEST_CASE( rsf_missed_blocks, testing_fixture )
chain.produce_blocks(1, 64);
BOOST_CHECK_EQUAL( rsf(),
"0000000000000000000000000000000000000000000000000000000000000000"
);
BOOST_CHECK_EQUAL( chain.producer_participation_rate(), pct(0) );
"1111111111111111111111111111111111111111111111111111111111111111"
); // For very small producer nets. All zeros otherwise.
BOOST_CHECK_EQUAL( chain.producer_participation_rate(), config::percent100 );
chain.produce_blocks(1, 63);
BOOST_CHECK_EQUAL( rsf(),
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eos/net_plugin/message_buffer.hpp>
#include <boost/test/unit_test.hpp>
#include <iostream>
namespace eosio {
using namespace std;
BOOST_AUTO_TEST_SUITE(message_buffer_tests)
constexpr auto def_buffer_size_mb = 4;
constexpr auto def_buffer_size = 1024*1024*def_buffer_size_mb;
/// Test default construction and buffer sequence generation
BOOST_AUTO_TEST_CASE(message_buffer_construction)
{
try {
eosio::message_buffer<def_buffer_size> mb;
BOOST_CHECK_EQUAL(mb.total_bytes(), def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
BOOST_CHECK_EQUAL(mb.read_ptr(), mb.write_ptr());
auto mbs = mb.get_buffer_sequence_for_boost_async_read();
auto mbsi = mbs.begin();
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_size_helper(*mbsi), def_buffer_size);
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_cast_helper(*mbsi), mb.write_ptr());
mbsi++;
BOOST_CHECK(mbsi == mbs.end());
}
FC_LOG_AND_RETHROW()
}
/// Test buffer growth and shrinking
BOOST_AUTO_TEST_CASE(message_buffer_growth)
{
try {
eosio::message_buffer<def_buffer_size> mb;
mb.add_buffer_to_chain();
BOOST_CHECK_EQUAL(mb.total_bytes(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
BOOST_CHECK_EQUAL(mb.read_ptr(), mb.write_ptr());
{
auto mbs = mb.get_buffer_sequence_for_boost_async_read();
auto mbsi = mbs.begin();
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_size_helper(*mbsi), def_buffer_size);
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_cast_helper(*mbsi), mb.write_ptr());
mbsi++;
BOOST_CHECK(mbsi != mbs.end());
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_size_helper(*mbsi), def_buffer_size);
BOOST_CHECK_NE(boost::asio::detail::buffer_cast_helper(*mbsi), nullptr);
mbsi++;
BOOST_CHECK(mbsi == mbs.end());
}
mb.advance_write_ptr(100);
BOOST_CHECK_EQUAL(mb.total_bytes(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 2 * def_buffer_size - 100);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 100);
BOOST_CHECK_NE(mb.read_ptr(), nullptr);
BOOST_CHECK_NE(mb.write_ptr(), nullptr);
BOOST_CHECK_EQUAL((mb.read_ptr() + 100), mb.write_ptr());
{
auto mbs = mb.get_buffer_sequence_for_boost_async_read();
auto mbsi = mbs.begin();
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_size_helper(*mbsi), def_buffer_size - 100);
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_cast_helper(*mbsi), mb.write_ptr());
mbsi++;
BOOST_CHECK(mbsi != mbs.end());
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_size_helper(*mbsi), def_buffer_size);
BOOST_CHECK_NE(boost::asio::detail::buffer_cast_helper(*mbsi), nullptr);
mbsi++;
BOOST_CHECK(mbsi == mbs.end());
}
mb.advance_read_ptr(50);
BOOST_CHECK_EQUAL(mb.total_bytes(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 2 * def_buffer_size - 100);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 50);
mb.advance_write_ptr(def_buffer_size);
BOOST_CHECK_EQUAL(mb.total_bytes(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), def_buffer_size - 100);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 50 + def_buffer_size);
// Moving read_ptr into second block should reset second block to first
mb.advance_read_ptr(def_buffer_size);
BOOST_CHECK_EQUAL(mb.total_bytes(), def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), def_buffer_size - 100);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 50);
// Moving read_ptr to write_ptr should shrink chain and reset ptrs
mb.advance_read_ptr(50);
BOOST_CHECK_EQUAL(mb.total_bytes(), def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
mb.add_buffer_to_chain();
BOOST_CHECK_EQUAL(mb.total_bytes(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
mb.advance_write_ptr(50);
BOOST_CHECK_EQUAL(mb.total_bytes(), 2 * def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 2 * def_buffer_size - 50);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 50);
// Moving read_ptr to write_ptr should shrink chain and reset ptrs
mb.advance_read_ptr(50);
BOOST_CHECK_EQUAL(mb.total_bytes(), def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), def_buffer_size);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
}
FC_LOG_AND_RETHROW()
}
/// Test peek and read across multiple buffers
BOOST_AUTO_TEST_CASE(message_buffer_peek_read)
{
try {
{
const uint32_t small = 32;
eosio::message_buffer<small> mb;
BOOST_CHECK_EQUAL(mb.total_bytes(), small);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), small);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
BOOST_CHECK_EQUAL(mb.read_ptr(), mb.write_ptr());
BOOST_CHECK_EQUAL(mb.read_index().first, 0);
BOOST_CHECK_EQUAL(mb.read_index().second, 0);
BOOST_CHECK_EQUAL(mb.write_index().first, 0);
BOOST_CHECK_EQUAL(mb.write_index().second, 0);
mb.add_space(100 - small);
BOOST_CHECK_EQUAL(mb.total_bytes(), 4 * small);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 4 * small);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
BOOST_CHECK_EQUAL(mb.read_ptr(), mb.write_ptr());
char* write_ptr = mb.write_ptr();
for (char ind = 0; ind < 100; ) {
*write_ptr = ind;
ind++;
if (ind % small == 0) {
mb.advance_write_ptr(small);
write_ptr = mb.write_ptr();
} else {
write_ptr++;
}
}
mb.advance_write_ptr(100 % small);
BOOST_CHECK_EQUAL(mb.total_bytes(), 4 * small);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 4 * small - 100);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 100);
BOOST_CHECK_NE((void*) mb.read_ptr(), (void*) mb.write_ptr());
BOOST_CHECK_EQUAL(mb.read_index().first, 0);
BOOST_CHECK_EQUAL(mb.read_index().second, 0);
BOOST_CHECK_EQUAL(mb.write_index().first, 3);
BOOST_CHECK_EQUAL(mb.write_index().second, 4);
char buffer[100];
auto index = mb.read_index();
mb.peek(buffer, 100, index);
for (int i=0; i < 100; i++) {
BOOST_CHECK_EQUAL(i, buffer[i]);
}
BOOST_CHECK_EQUAL(mb.total_bytes(), 4 * small);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), 4 * small - 100);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 100);
BOOST_CHECK_NE((void*) mb.read_ptr(), (void*) mb.write_ptr());
char buffer2[100];
mb.read(buffer2, 100);
for (int i=0; i < 100; i++) {
BOOST_CHECK_EQUAL(i, buffer2[i]);
}
BOOST_CHECK_EQUAL(mb.total_bytes(), small);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), small);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
BOOST_CHECK_EQUAL(mb.read_ptr(), mb.write_ptr());
}
}
FC_LOG_AND_RETHROW()
}
/// Test automatic allocation when advancing the read_ptr to the end.
BOOST_AUTO_TEST_CASE(message_buffer_write_ptr_to_end)
{
try {
{
const uint32_t small = 32;
eosio::message_buffer<small> mb;
BOOST_CHECK_EQUAL(mb.total_bytes(), small);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), small);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), 0);
BOOST_CHECK_EQUAL(mb.read_ptr(), mb.write_ptr());
BOOST_CHECK_EQUAL(mb.read_index().first, 0);
BOOST_CHECK_EQUAL(mb.read_index().second, 0);
BOOST_CHECK_EQUAL(mb.write_index().first, 0);
BOOST_CHECK_EQUAL(mb.write_index().second, 0);
char* write_ptr = mb.write_ptr();
for (char ind = 0; ind < small; ind++) {
*write_ptr = ind;
write_ptr++;
}
mb.advance_write_ptr(small);
BOOST_CHECK_EQUAL(mb.total_bytes(), 2 * small);
BOOST_CHECK_EQUAL(mb.bytes_to_write(), small);
BOOST_CHECK_EQUAL(mb.bytes_to_read(), small);
BOOST_CHECK_NE((void*) mb.read_ptr(), (void*) mb.write_ptr());
BOOST_CHECK_EQUAL(mb.read_index().first, 0);
BOOST_CHECK_EQUAL(mb.read_index().second, 0);
BOOST_CHECK_EQUAL(mb.write_index().first, 1);
BOOST_CHECK_EQUAL(mb.write_index().second, 0);
auto mbs = mb.get_buffer_sequence_for_boost_async_read();
auto mbsi = mbs.begin();
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_size_helper(*mbsi), small);
BOOST_CHECK_EQUAL(boost::asio::detail::buffer_cast_helper(*mbsi), mb.write_ptr());
BOOST_CHECK_EQUAL(mb.read_ptr()+small, mb.write_ptr());
mbsi++;
BOOST_CHECK(mbsi == mbs.end());
}
}
FC_LOG_AND_RETHROW()
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace eosio
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册