merging changes

This commit is contained in:
Daniel Larimer 2015-08-20 08:49:18 -04:00
commit 714261b02a
12 changed files with 98 additions and 18 deletions

View file

@ -83,7 +83,7 @@ Witness node
The role of the witness node is to broadcast transactions, download blocks, and optionally sign them. The role of the witness node is to broadcast transactions, download blocks, and optionally sign them.
``` ```
./witness_node --rpc-endpoint 127.0.0.1:8090 --enable-stale-production -w '"1.6.0"' '"1.6.1"' '"1.6.2"' '"1.6.3"' '"1.6.4"' '"1.6.5"' '"1.6.6"' '"1.6.7"' '"1.6.8"' '"1.6.9"' ./witness_node --rpc-endpoint 127.0.0.1:8090 --enable-stale-production -w '"1.6.0"' '"1.6.1"' '"1.6.2"' '"1.6.3"' '"1.6.4"' '"1.6.5"' '"1.6.6"' '"1.6.7"' '"1.6.8"' '"1.6.9"' '"1.6.10"' '"1.6.11"' '"1.6.12"' '"1.6.13"' '"1.6.14"' '"1.6.15"' '"1.6.16"' '"1.6.17"' '"1.6.18"' '"1.6.19"' '"1.6.20"' '"1.6.21"' '"1.6.22"' '"1.6.23"' '"1.6.24"' '"1.6.25"' '"1.6.26"' '"1.6.27"' '"1.6.28"' '"1.6.29"' '"1.6.30"' '"1.6.31"' '"1.6.32"' '"1.6.33"' '"1.6.34"' '"1.6.35"' '"1.6.36"' '"1.6.37"' '"1.6.38"' '"1.6.39"' '"1.6.40"' '"1.6.41"' '"1.6.42"' '"1.6.43"' '"1.6.44"' '"1.6.45"' '"1.6.46"' '"1.6.47"' '"1.6.48"' '"1.6.49"' '"1.6.50"' '"1.6.51"' '"1.6.52"' '"1.6.53"' '"1.6.54"' '"1.6.55"' '"1.6.56"' '"1.6.57"' '"1.6.58"' '"1.6.59"' '"1.6.60"' '"1.6.61"' '"1.6.62"' '"1.6.63"' '"1.6.64"' '"1.6.65"' '"1.6.66"' '"1.6.67"' '"1.6.68"' '"1.6.69"' '"1.6.70"' '"1.6.71"' '"1.6.72"' '"1.6.73"' '"1.6.74"' '"1.6.75"' '"1.6.76"' '"1.6.77"' '"1.6.78"' '"1.6.79"' '"1.6.80"' '"1.6.81"' '"1.6.82"' '"1.6.83"' '"1.6.84"' '"1.6.85"' '"1.6.86"' '"1.6.87"' '"1.6.88"' '"1.6.89"' '"1.6.90"' '"1.6.91"' '"1.6.92"' '"1.6.93"' '"1.6.94"' '"1.6.95"' '"1.6.96"' '"1.6.97"' '"1.6.98"' '"1.6.99"' '"1.6.100"'
``` ```
Running specific tests Running specific tests

View file

@ -313,6 +313,11 @@ namespace detail {
return it->second; return it->second;
} }
void set_api_access_info(const string& username, api_access_info&& permissions)
{
_apiaccess.permission_map.insert(std::make_pair(username, std::move(permissions)));
}
/** /**
* If delegate has the item, the network has no need to fetch it. * If delegate has the item, the network has no need to fetch it.
*/ */
@ -668,6 +673,11 @@ optional< api_access_info > application::get_api_access_info( const string& user
return my->get_api_access_info( username ); return my->get_api_access_info( username );
} }
void application::set_api_access_info(const string& username, api_access_info&& permissions)
{
my->set_api_access_info(username, std::move(permissions));
}
bool application::is_finished_syncing() const bool application::is_finished_syncing() const
{ {
return my->_is_finished_syncing; return my->_is_finished_syncing;

View file

@ -76,6 +76,7 @@ namespace graphene { namespace app {
void set_block_production(bool producing_blocks); void set_block_production(bool producing_blocks);
fc::optional< api_access_info > get_api_access_info( const string& username )const; fc::optional< api_access_info > get_api_access_info( const string& username )const;
void set_api_access_info(const string& username, api_access_info&& permissions);
bool is_finished_syncing()const; bool is_finished_syncing()const;
/// Emitted when syncing finishes (is_finished_syncing will return true) /// Emitted when syncing finishes (is_finished_syncing will return true)

View file

@ -67,13 +67,14 @@ void fork_database::_push_block(const item_ptr& item)
FC_ASSERT( item->num > std::max<int64_t>( 0, int64_t(_head->num) - (_max_size) ), FC_ASSERT( item->num > std::max<int64_t>( 0, int64_t(_head->num) - (_max_size) ),
"attempting to push a block that is too old", "attempting to push a block that is too old",
("item->num",item->num)("head",_head->num)("max_size",_max_size)); ("item->num",item->num)("head",_head->num)("max_size",_max_size));
FC_ASSERT( item->num < _head->num + 32 ); FC_ASSERT( item->num < _head->num + MAX_BLOCK_REORDERING );
} }
if( _head && item->previous_id() != block_id_type() ) if( _head && item->previous_id() != block_id_type() )
{ {
auto itr = _index.get<block_id>().find(item->previous_id()); auto& index = _index.get<block_id>();
GRAPHENE_ASSERT(itr != _index.get<block_id>().end(), unlinkable_block_exception, "block does not link to known chain"); auto itr = index.find(item->previous_id());
GRAPHENE_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain");
FC_ASSERT(!(*itr)->invalid); FC_ASSERT(!(*itr)->invalid);
item->prev = *itr; item->prev = *itr;
} }
@ -99,7 +100,6 @@ void fork_database::_push_block(const item_ptr& item)
void fork_database::_push_next( const item_ptr& new_item ) void fork_database::_push_next( const item_ptr& new_item )
{ {
auto& prev_idx = _unlinked_index.get<by_previous>(); auto& prev_idx = _unlinked_index.get<by_previous>();
vector<item_ptr> newly_inserted;
auto itr = prev_idx.find( new_item->id ); auto itr = prev_idx.find( new_item->id );
while( itr != prev_idx.end() ) while( itr != prev_idx.end() )

View file

@ -63,6 +63,8 @@ namespace graphene { namespace chain {
{ {
public: public:
typedef vector<item_ptr> branch_type; typedef vector<item_ptr> branch_type;
/// The maximum number of blocks that may be skipped in an out-of-order push
const static int MAX_BLOCK_REORDERING = 32;
fork_database(); fork_database();
void reset(); void reset();

View file

@ -16,14 +16,10 @@
BlockChain::BlockChain() BlockChain::BlockChain()
: chainThread(new fc::thread("chainThread")), : chainThread(new fc::thread("chainThread")),
fcTaskScheduler(new QTimer(this)), grapheneApp(new graphene::app::application),
grapheneApp(new graphene::app::application) webUsername(QStringLiteral("webui")),
{ webPassword(QString::fromStdString(fc::sha256::hash(fc::ecc::private_key::generate())))
fcTaskScheduler->setInterval(100); {}
fcTaskScheduler->setSingleShot(false);
connect(fcTaskScheduler, &QTimer::timeout, [] {fc::yield();});
fcTaskScheduler->start();
}
BlockChain::~BlockChain() { BlockChain::~BlockChain() {
startFuture.cancel_and_wait(__FUNCTION__); startFuture.cancel_and_wait(__FUNCTION__);
@ -50,6 +46,13 @@ void BlockChain::start()
grapheneApp->initialize_plugins(map); grapheneApp->initialize_plugins(map);
grapheneApp->startup(); grapheneApp->startup();
grapheneApp->startup_plugins(); grapheneApp->startup_plugins();
graphene::app::api_access_info webPermissions;
auto passHash = fc::sha256::hash(webPassword.toStdString());
webPermissions.password_hash_b64 = fc::base64_encode(passHash.data(), passHash.data_size());
webPermissions.password_salt_b64 = fc::base64_encode("");
webPermissions.allowed_apis = {"database_api", "network_broadcast_api", "network_node_api", "history_api"};
grapheneApp->set_api_access_info(webUsername.toStdString(), std::move(webPermissions));
} catch (const fc::exception& e) { } catch (const fc::exception& e) {
elog("Crap went wrong: ${e}", ("e", e.to_detail_string())); elog("Crap went wrong: ${e}", ("e", e.to_detail_string()));
} }

View file

@ -10,11 +10,14 @@ namespace fc { class thread; }
namespace graphene { namespace app { class application; } } namespace graphene { namespace app { class application; } }
class BlockChain : public QObject { class BlockChain : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString webUsername MEMBER webUsername CONSTANT)
Q_PROPERTY(QString webPassword MEMBER webPassword CONSTANT)
fc::thread* chainThread; fc::thread* chainThread;
QTimer* fcTaskScheduler;
graphene::app::application* grapheneApp; graphene::app::application* grapheneApp;
fc::future<void> startFuture; fc::future<void> startFuture;
QString webUsername;
QString webPassword;
public: public:
BlockChain(); BlockChain();

View file

@ -12,7 +12,11 @@ Window {
BlockChain { BlockChain {
id: blockChain id: blockChain
onStarted: webView.url = "qrc:/index.html" onStarted: {
var url = "qrc:/index.html#authTokens/" + webUsername + ":" + webPassword
console.log("Loading %1 in web view".arg(url))
webView.url = url
}
} }
Component.onCompleted: blockChain.start() Component.onCompleted: blockChain.start()

View file

@ -35,6 +35,8 @@ void ChainDataModel::setDatabaseAPI(fc::api<database_api> dbapi) {
m_db_api->subscribe_to_objects([this](const variant& d) { m_db_api->subscribe_to_objects([this](const variant& d) {
m_dynamic_global_properties = d.as<dynamic_global_property_object>(); m_dynamic_global_properties = d.as<dynamic_global_property_object>();
}, {m_dynamic_global_properties.id}); }, {m_dynamic_global_properties.id});
m_chain_properties = m_db_api->get_chain_properties();
}); });
} }

View file

@ -61,6 +61,7 @@ public:
const graphene::chain::global_property_object& global_properties() const { return m_global_properties; } const graphene::chain::global_property_object& global_properties() const { return m_global_properties; }
const graphene::chain::dynamic_global_property_object& dynamic_global_properties() const { return m_dynamic_global_properties; } const graphene::chain::dynamic_global_property_object& dynamic_global_properties() const { return m_dynamic_global_properties; }
const graphene::chain::chain_property_object& chain_properties() const { return m_chain_properties; }
public Q_SLOTS: public Q_SLOTS:
void broadcast(Transaction* transaction); void broadcast(Transaction* transaction);
@ -78,6 +79,7 @@ private:
graphene::chain::global_property_object m_global_properties; graphene::chain::global_property_object m_global_properties;
graphene::chain::dynamic_global_property_object m_dynamic_global_properties; graphene::chain::dynamic_global_property_object m_dynamic_global_properties;
graphene::chain::chain_property_object m_chain_properties;
ObjectId m_account_query_num = -1; ObjectId m_account_query_num = -1;
account_multi_index_type m_accounts; account_multi_index_type m_accounts;

View file

@ -100,7 +100,7 @@ void GrapheneApplication::signTransaction(Transaction* transaction) const
return &model()->getAccount(id.instance.value)->accountObject().owner; return &model()->getAccount(id.instance.value)->accountObject().owner;
}; };
auto& chainId = model()->global_properties().chain_id; auto& chainId = model()->chain_properties().chain_id;
auto& trx = transaction->internalTransaction(); auto& trx = transaction->internalTransaction();
trx.set_reference_block(model()->dynamic_global_properties().head_block_id); trx.set_reference_block(model()->dynamic_global_properties().head_block_id);
flat_set<public_key_type> pubKeys = wallet()->getAvailablePrivateKeys(); flat_set<public_key_type> pubKeys = wallet()->getAvailablePrivateKeys();

View file

@ -276,6 +276,59 @@ BOOST_AUTO_TEST_CASE( fork_blocks )
} }
} }
BOOST_AUTO_TEST_CASE( out_of_order_blocks )
{
try {
fc::temp_directory data_dir1( graphene::utilities::temp_directory_path() );
fc::temp_directory data_dir2( graphene::utilities::temp_directory_path() );
database db1;
db1.open(data_dir1.path(), make_genesis);
database db2;
db2.open(data_dir2.path(), make_genesis);
BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() );
auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
auto b1 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b2 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b3 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b4 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b5 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b6 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b7 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b8 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b9 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b10 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b11 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
auto b12 = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1).first, init_account_priv_key, database::skip_nothing);
BOOST_CHECK_EQUAL(db1.head_block_num(), 12);
BOOST_CHECK_EQUAL(db2.head_block_num(), 0);
PUSH_BLOCK( db2, b1 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 1);
PUSH_BLOCK( db2, b3 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 1);
PUSH_BLOCK( db2, b2 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 3);
PUSH_BLOCK( db2, b5 );
PUSH_BLOCK( db2, b6 );
PUSH_BLOCK( db2, b7 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 3);
PUSH_BLOCK( db2, b4 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 7);
PUSH_BLOCK( db2, b8 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 8);
PUSH_BLOCK( db2, b11 );
PUSH_BLOCK( db2, b10 );
PUSH_BLOCK( db2, b12 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 8);
PUSH_BLOCK( db2, b9 );
BOOST_CHECK_EQUAL(db2.head_block_num(), 12);
} catch (fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}
BOOST_AUTO_TEST_CASE( undo_pending ) BOOST_AUTO_TEST_CASE( undo_pending )
{ {
try { try {