merging changes
This commit is contained in:
commit
714261b02a
12 changed files with 98 additions and 18 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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() )
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue