Merge branch 'master' of github.com:cryptonomex/graphene

This commit is contained in:
Daniel Larimer 2015-07-13 17:24:29 -04:00
commit 98e761c9c2
22 changed files with 311 additions and 41 deletions

View file

@ -82,7 +82,6 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
obj.options = o.options;
});
const auto& global_properties = db().get_global_properties();
const auto& dynamic_properties = db().get_dynamic_global_properties();
db().modify(dynamic_properties, [](dynamic_global_property_object& p) {
++p.accounts_registered_this_interval;

View file

@ -73,14 +73,4 @@ node_property_object& database::node_properties()
return _node_property_object;
}
double database::witness_participation_rate()const
{
if( head_block_num() < 10 ) return 1; // sample size is too small
uint32_t produced = std::min<uint32_t>( head_block_num()-1, 100 );
auto prior = fetch_block_by_number( head_block_num() - produced );
auto delta_time = head_block_time() - prior->timestamp;
auto expected_slots = delta_time.to_seconds() / get_global_properties().parameters.block_interval;
return double(produced) / expected_slots;
}
} }

View file

@ -525,6 +525,8 @@ void database::init_genesis(const genesis_state_type& genesis_state)
_wso.scheduler.produce_schedule(rng);
_wso.last_scheduling_block = 0;
_wso.recent_slots_filled = fc::uint128::max_value();
});
assert( wso.id == witness_schedule_id_type() );

View file

@ -141,6 +141,16 @@ void database::update_witness_schedule(const signed_block& next_block)
memcpy(_wso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
}
_wso.last_scheduling_block = next_block.block_num();
_wso.recent_slots_filled = (
(_wso.recent_slots_filled << 1)
+ 1) << (schedule_slot - 1);
});
}
uint32_t database::witness_participation_rate()const
{
const witness_schedule_object& wso = get(witness_schedule_id_type());
return uint64_t(GRAPHENE_100_PERCENT) * wso.recent_slots_filled.popcount() / 128;
}
} }

View file

@ -138,9 +138,9 @@ namespace graphene { namespace chain {
/**
* Calculate the percent of block production slots that were missed in the
* past 100 blocks.
* past 128 blocks, not including the current block.
*/
double witness_participation_rate()const;
uint32_t witness_participation_rate()const;
void add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts );
const flat_map<uint32_t,block_id_type> get_checkpoints()const { return _checkpoints; }

View file

@ -16,6 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <fc/uint128.hpp>
#include <graphene/chain/protocol/chain_parameters.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/db/object.hpp>

View file

@ -19,6 +19,7 @@
// needed to serialize witness_scheduler
#include <fc/container/deque.hpp>
#include <fc/uint128.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/witness_scheduler.hpp>
@ -57,6 +58,12 @@ class witness_schedule_object : public abstract_object<witness_schedule_object>
uint32_t last_scheduling_block;
uint64_t slots_since_genesis = 0;
fc::array< char, sizeof(secret_hash_type) > rng_seed;
/**
* Not necessary for consensus, but used for figuring out the participation rate.
* The nth bit is 0 if the nth slot was unfilled, else it is 1.
*/
fc::uint128 recent_slots_filled;
};
} }
@ -77,4 +84,5 @@ FC_REFLECT_DERIVED( graphene::chain::witness_schedule_object, (graphene::chain::
(last_scheduling_block)
(slots_since_genesis)
(rng_seed)
(recent_slots_filled)
)

@ -1 +1 @@
Subproject commit 0391665471b4dffb7af951853a777565a7ae9a74
Subproject commit 5f43c06bae6d03e319dd2f230fe7cbd74399a773

View file

@ -57,7 +57,7 @@ private:
boost::program_options::variables_map _options;
bool _production_enabled = false;
bool _consecutive_production_enabled = false;
int _required_witness_participation = 33;
uint32_t _required_witness_participation = 33 * GRAPHENE_1_PERCENT;
std::map<chain::public_key_type, fc::ecc::private_key> _private_keys;
std::set<chain::witness_id_type> _witnesses;

View file

@ -39,7 +39,7 @@ void witness_plugin::plugin_set_program_options(
string witness_id_example = fc::json::to_string(chain::witness_id_type());
command_line_options.add_options()
("enable-stale-production", bpo::bool_switch()->notifier([this](bool e){_production_enabled = e;}), "Enable block production, even if the chain is stale.")
("required-participation", bpo::bool_switch()->notifier([this](int e){_required_witness_participation = e;}), "Percent of witnesses (0-99) that must be participating in order to produce blocks")
("required-participation", bpo::bool_switch()->notifier([this](int e){_required_witness_participation = uint32_t(e*GRAPHENE_1_PERCENT);}), "Percent of witnesses (0-99) that must be participating in order to produce blocks")
("allow-consecutive", bpo::bool_switch()->notifier([this](bool e){_consecutive_production_enabled = e;}), "Allow block production, even if the last block was produced by the same witness.")
("witness-id,w", bpo::value<vector<string>>()->composing()->multitoken(),
("ID of witness controlled by this node (e.g. " + witness_id_example + ", quotes are required, may specify multiple times)").c_str())
@ -191,11 +191,11 @@ void witness_plugin::block_production_loop()
return false;
}
double prate = db.witness_participation_rate();
if( int(100*prate) < _required_witness_participation )
uint32_t prate = db.witness_participation_rate();
if( prate < _required_witness_participation )
{
elog("Not producing block because node appers to be on a minority fork with only ${x}% witness participation",
("x",uint32_t(100*prate) ) );
("x",uint32_t(100*uint64_t(prate) / GRAPHENE_1_PERCENT) ) );
return false;
}

View file

@ -11,14 +11,25 @@
#include <fc/thread/thread.hpp>
#include <graphene/app/api.hpp>
#include <QCryptographicHash>
#include <QObject>
#include <QQmlListProperty>
#include <QtQml>
using boost::multi_index_container;
using namespace boost::multi_index;
Q_DECLARE_METATYPE(std::function<void()>)
class Crypto {
Q_GADGET
public:
Q_INVOKABLE QString sha256(QByteArray data) {
return QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex();
}
};
QML_DECLARE_TYPE(Crypto)
class Asset : public QObject {
Q_OBJECT

View file

@ -4,7 +4,6 @@
#include "ClientDataModel.hpp"
int main(int argc, char *argv[])
{
fc::thread::current().set_name( "main" );
@ -22,6 +21,9 @@ int main(int argc, char *argv[])
qmlRegisterType<GrapheneApplication>("Graphene.Client", 0, 1, "GrapheneApplication");
QQmlApplicationEngine engine;
QVariant crypto;
crypto.setValue(Crypto());
engine.rootContext()->setContextProperty("Crypto", crypto);
#ifdef NDEBUG
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
#else

1
programs/light_client/qml/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.depends

View file

@ -5,6 +5,7 @@ import QtQuick.Dialogs 1.2
Rectangle {
id: greySheet
state: "HIDDEN"
color: Qt.rgba(0, 0, 0, showOpacity)
property real showOpacity: .5
property int animationTime: 300
@ -18,8 +19,11 @@ Rectangle {
/// Emitted when closed, following fade-out animation
signal closed
function showForm(formType, closedCallback) {
formLoader.sourceComponent = formType
function showForm(formType, params, closedCallback) {
if (formType.status === Component.Error)
console.log(formType.errorString())
formContainer.data = [formType.createObject(formContainer, params)]
if (closedCallback instanceof Function)
internal.callback = closedCallback
state = "SHOWN"
@ -35,12 +39,12 @@ Rectangle {
acceptedButtons: Qt.AllButtons
}
MouseArea {
anchors.fill: formLoader
anchors.fill: formContainer
acceptedButtons: Qt.AllButtons
onClicked: mouse.accepted = true
}
Loader {
id: formLoader
Item {
id: formContainer
anchors.centerIn: parent
width: parent.width / 2
height: parent.height / 2
@ -51,7 +55,7 @@ Rectangle {
name: "HIDDEN"
PropertyChanges {
target: greySheet
color: Qt.rgba(0, 0, 0, 0)
opacity: 0
enabled: false
}
StateChangeScript {
@ -63,10 +67,12 @@ Rectangle {
StateChangeScript {
name: "postHidden"
script: {
console.log("Post")
greySheet.closed()
formLoader.sourceComponent = undefined
formContainer.data = []
if (internal.callback instanceof Function)
internal.callback()
internal.callback = undefined
}
}
},
@ -74,7 +80,7 @@ Rectangle {
name: "SHOWN"
PropertyChanges {
target: greySheet
color: Qt.rgba(0, 0, 0, showOpacity)
opacity: 1
enabled: true
}
StateChangeScript {
@ -95,22 +101,28 @@ Rectangle {
Transition {
from: "HIDDEN"
to: "SHOWN"
ScriptAction { scriptName: "preShown" }
ColorAnimation {
target: greySheet
duration: animationTime
SequentialAnimation {
ScriptAction { scriptName: "preShown" }
PropertyAnimation {
target: greySheet
property: "opacity"
duration: animationTime
}
ScriptAction { scriptName: "postShown" }
}
ScriptAction { scriptName: "postShown" }
},
Transition {
from: "SHOWN"
to: "HIDDEN"
ScriptAction { scriptName: "preHidden" }
ColorAnimation {
target: greySheet
duration: animationTime
SequentialAnimation {
ScriptAction { scriptName: "preHidden" }
PropertyAnimation {
target: greySheet
property: "opacity"
duration: animationTime
}
ScriptAction { scriptName: "postHidden" }
}
ScriptAction { scriptName: "postHidden" }
}
]

View file

@ -0,0 +1,12 @@
pragma Singleton
import QtQuick 2.5
import QtQuick.Window 2.2
Item {
function mm(millimeters) {
return Screen.pixelDensity * millimeters
}
function cm(centimeters) {
return mm(centimeters * 10)
}
}

View file

@ -1,8 +1,60 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import "."
import "jdenticon/jdenticon-1.0.1.min.js" as Jdenticon
Rectangle {
anchors.fill: parent
Component.onCompleted: console.log("Made a transfer form")
Component.onDestruction: console.log("Destroyed a transfer form")
Column {
anchors.centerIn: parent
RowLayout {
Canvas {
id: identicon
width: Scaling.cm(2)
height: Scaling.cm(2)
contextType: "2d"
onPaint: {
if (nameField.text)
Jdenticon.draw(identicon, nameField.text)
else {
var context = identicon.context
context.reset()
var draw_circle = function(context, x, y, radius) {
context.beginPath()
context.arc(x, y, radius, 0, 2 * Math.PI, false)
context.fillStyle = "rgba(0, 0, 0, 0.1)"
context.fill()
}
var size = Math.min(identicon.height, identicon.width)
var centerX = size / 2
var centerY = size / 2
var radius = size/15
draw_circle(context, centerX, centerY, radius)
draw_circle(context, 2*radius, 2*radius, radius)
draw_circle(context, centerX, 2*radius, radius)
draw_circle(context, size - 2*radius, 2*radius, radius)
draw_circle(context, size - 2*radius, centerY, radius)
draw_circle(context, size - 2*radius, size - 2*radius, radius)
draw_circle(context, centerX, size - 2*radius, radius)
draw_circle(context, 2*radius, size - 2*radius, radius)
draw_circle(context, 2*radius, centerY, radius)
}
}
}
TextField {
id: nameField
Layout.fillWidth: true
onTextChanged: identicon.requestPaint()
}
}
}
}

View file

@ -0,0 +1,18 @@
// Jdenticon 1.0.1 | jdenticon.com | zlib licensed | (c) 2014-2015 Daniel Mester Pirttijärvi
/*Alteration to official Jdenticon code: make jdenticon() a variable in this context instead of a property of window*/
var jdenticon=function(){function h(){}function n(b,a,c,d){this.h=b;this.i=a;this.k=c;this.f=d}function u(b,a){this.e=b;this.g=a||n.q;b.beginPath()}function r(b,a,c){var d=(b="string"===typeof b?document.querySelector(b):b).getContext("2d");c=Math.min(b.width)*(1-2*(c===t?.08:c));d.save();d.clearRect(0,0,b.width,b.height);d.translate(0|(b.width-c)/2,0|(b.height-c)/2);v(d,a||b.getAttribute("data-jdenticon-hash"),c);d.restore()}function v(b,a,c){function d(b,c,d,e,g){e=e?parseInt(a.charAt(e),16):
0;c=c[parseInt(a.charAt(d),16)%c.length];var f;for(d=0;d<g.length;d++)f=new n(g[d][0]*p,g[d][1]*p,p,e++%4),f=new u(b,f),c(f,p,d),f.fill()}function e(a){if(0<=a.indexOf(k))for(var b=0;b<a.length;b++)if(0<=l.indexOf(a[b]))return!0}function g(a){b.fillStyle=m[l[a]].toString()}if(30>c)throw Error("Jdenticon cannot render identicons smaller than 30 pixels.");if(!/^[0-9a-f]{10,}$/i.test(a))throw Error("Invalid hash passed to Jdenticon.");c|=0;for(var p=2*(0|c/8),f=parseInt(a.substr(-7),16)/268435455,m=
[h.o(76,76,76),h.m(f,.6),h.o(230,230,230),h.m(f,.8),h.n(f,.4)],l=[],k,f=0;3>f;f++){k=parseInt(a.charAt(8+f),16)%m.length;if(e([0,4])||e([2,3]))k=1;l.push(k)}b.clearRect(0,0,c,c);g(0);d(b,w,2,3,[[1,0],[2,0],[2,3],[1,3],[0,1],[3,1],[3,2],[0,2]]);g(1);d(b,w,4,5,[[0,0],[3,0],[3,3],[0,3]]);g(2);d(b,y,1,null,[[1,1],[2,1],[2,2],[1,2]])}function q(){for(var b,a=document.getElementsByTagName("canvas"),c=0;c<a.length;c++)(b=a[c].getAttribute("data-jdenticon-hash"))&&r(a[c],b)}var t,x=window.jQuery;h.o=function(b,
a,c){var d=new h;d.p="rgba("+(b&255)+","+(a&255)+","+(c&255)+","+(void 0===t?1:void 0)+")";return d};h.n=function(b,a){var c=new h;c.p="hsla("+(360*b|0)+",50%,"+(100*a|0)+"%,"+(void 0===t?1:void 0)+")";return c};h.m=function(b,a){return h.n(b,1-[.95,1,1,1,.7,.8,.8][6*b+.5|0]*(1-a))};h.prototype={toString:function(){return this.p}};n.q=new n(0,0,0,0);n.prototype={j:function(b,a,c,d){var e=this.h+this.k,g=this.i+this.k;return 1===this.f?[e-a-(d||0),this.i+b]:2===this.f?[e-b-(c||0),g-a-(d||0)]:3===this.f?
[this.h+a,g-b-(c||0)]:[this.h+b,this.i+a]}};u.prototype={c:function(b,a){var c=a?-2:2,d=a?b.length-2:0,e=this.e;e.moveTo.apply(e,this.g.j(b[d],b[d+1]));for(d+=c;d<b.length&&0<=d;d+=c)e.lineTo.apply(e,this.g.j(b[d],b[d+1]));e.closePath()},d:function(b,a,c,d,e){var g=this.e;a=this.g.j(b,a,c,d);b=a[0];a=a[1];var h=c/2*.5522848,f=d/2*.5522848,m=b+c,l=a+d;c=b+c/2;var k=a+d/2;e&&(l=a,a+=d,f=-f);g.moveTo(b,k);g.bezierCurveTo(b,k-f,c-h,a,c,a);g.bezierCurveTo(c+h,a,m,k-f,m,k);g.bezierCurveTo(m,k+f,c+h,l,c,
l);g.bezierCurveTo(c-h,l,b,k+f,b,k);g.closePath()},a:function(b,a,c,d,e){this.c([b,a,b+c,a,b+c,a+d,b,a+d],e)},b:function(b,a,c,d,e,g){b=[b+c,a,b+c,a+d,b,a+d,b,a];b.splice((e||0)%4,2);this.c(b,g)},l:function(b,a,c,d,e){this.c([b+c/2,a,b+c,a+d/2,b+c/2,a+d,b,a+d/2],e)},fill:function(){this.e.fill()}};var y=[function(b,a){var c=.42*a;b.c([0,0,a,0,a,a-2*c,a-c,a,0,a])},function(b,a){var c=0|.4*a;b.b(a-c,a-2*c,c,2*c,1)},function(b,a){var c=0|a/3;b.a(c,c,a-c,a-c)},function(b,a){var c=0|.1*a,d=0|.25*a;b.a(d,
d,a-c-d,a-c-d)},function(b,a){var c=0|.15*a,d=0|.5*a;b.d(a-d-c,a-d-c,d,d)},function(b,a){var c=.1*a,d=4*c;b.a(0,0,a,a);b.c([d,d,a-c,d,d+(a-d-c)/2,a-c],!0)},function(b,a){b.b(0,0,a,a,0)},function(b,a){b.b(a/2,a/2,a/2,a/2,0)},function(b,a){b.a(0,0,a,a/2);b.a(0,a/2,a/2,a/2);b.b(a/2,a/2,a/2,a/2,1)},function(b,a){var c=0|.14*a,d=0|.35*a;b.a(0,0,a,a);b.a(d,d,a-d-c,a-d-c,!0)},function(b,a){var c=.12*a,d=3*c;b.a(0,0,a,a);b.d(d,d,a-c-d,a-c-d,!0)},function(b,a){b.b(a/2,a/2,a/2,a/2,3)},function(b,a){var c=.25*
a;b.a(0,0,a,a);b.l(c,c,a-c,a-c,!0)},function(b,a,c){var d=.4*a;a*=1.2;c||b.d(d,d,a,a)}],w=[function(b,a){b.b(0,0,a,a,0)},function(b,a){b.b(0,a/2,a,a/2,0)},function(b,a){b.l(0,0,a,a)},function(b,a){var c=a/6;b.d(c,c,a-2*c,a-2*c)}];q.drawIcon=v;q.update=r;x&&(x.fn.jdenticon=function(b,a){this.each(function(c,d){r(d,b,a)});return this});/*Alteration to official Jdenticon code: Removed call to schedule a render immediately on load*/return q}();
// The following functions were added, and are not part of the official Jdenticon code
/// @param canvas The canvas to draw on
/// @param data The data to generate an identicon for (this will be hashed to generate the identicon)
function draw(canvas, data) {
jdenticon.drawIcon(canvas.context, Crypto.sha256(data), Math.min(canvas.width, canvas.height))
}

View file

@ -0,0 +1,21 @@

Jdenticon
Copyright (c) 2014 Daniel Mester Pirttijärvi
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View file

@ -1,6 +1,7 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Window 2.2
import Qt.labs.settings 1.0
@ -47,9 +48,10 @@ ApplicationWindow {
anchors.centerIn: parent
Button {
text: "Transfer"
onClicked: formBox.showForm(Qt.createComponent("TransferForm.qml"), function() {
console.log("Closed form")
})
onClicked: formBox.showForm(Qt.createComponent("TransferForm.qml"), {},
function() {
console.log("Closed form")
})
}
TextField {
id: nameField
@ -80,6 +82,7 @@ ApplicationWindow {
}
}
}
}
FormBox {

View file

@ -3,6 +3,8 @@
<file>main.qml</file>
<file>TransferForm.qml</file>
<file>FormBox.qml</file>
<file>jdenticon/jdenticon-1.0.1.min.js</file>
<file>Scaling.qml</file>
</qresource>
</RCC>

View file

@ -0,0 +1 @@
singleton Scaling Scaling.qml

View file

@ -907,4 +907,128 @@ BOOST_FIXTURE_TEST_CASE( witness_scheduler_missed_blocks, database_fixture )
});
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE( rsf_missed_blocks, database_fixture )
{
try
{
generate_block();
auto rsf = [&]() -> string
{
fc::uint128 rsf = db.get( witness_schedule_id_type() ).recent_slots_filled;
string result = "";
result.reserve(128);
for( int i=0; i<128; i++ )
{
result += ((rsf.lo & 1) == 0) ? '0' : '1';
rsf >>= 1;
}
return result;
};
auto pct = []( uint32_t x ) -> uint32_t
{
return uint64_t( GRAPHENE_100_PERCENT ) * x / 128;
};
BOOST_CHECK_EQUAL( rsf(),
"1111111111111111111111111111111111111111111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), GRAPHENE_100_PERCENT );
generate_block( ~0, init_account_priv_key, 1 );
BOOST_CHECK_EQUAL( rsf(),
"0111111111111111111111111111111111111111111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(127) );
generate_block( ~0, init_account_priv_key, 1 );
BOOST_CHECK_EQUAL( rsf(),
"0101111111111111111111111111111111111111111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(126) );
generate_block( ~0, init_account_priv_key, 2 );
BOOST_CHECK_EQUAL( rsf(),
"0010101111111111111111111111111111111111111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(124) );
generate_block( ~0, init_account_priv_key, 3 );
BOOST_CHECK_EQUAL( rsf(),
"0001001010111111111111111111111111111111111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(121) );
generate_block( ~0, init_account_priv_key, 5 );
BOOST_CHECK_EQUAL( rsf(),
"0000010001001010111111111111111111111111111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(116) );
generate_block( ~0, init_account_priv_key, 8 );
BOOST_CHECK_EQUAL( rsf(),
"0000000010000010001001010111111111111111111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(108) );
generate_block( ~0, init_account_priv_key, 13 );
BOOST_CHECK_EQUAL( rsf(),
"0000000000000100000000100000100010010101111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(95) );
generate_block();
BOOST_CHECK_EQUAL( rsf(),
"1000000000000010000000010000010001001010111111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(95) );
generate_block();
BOOST_CHECK_EQUAL( rsf(),
"1100000000000001000000001000001000100101011111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(95) );
generate_block();
BOOST_CHECK_EQUAL( rsf(),
"1110000000000000100000000100000100010010101111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(95) );
generate_block();
BOOST_CHECK_EQUAL( rsf(),
"1111000000000000010000000010000010001001010111111111111111111111"
"1111111111111111111111111111111111111111111111111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(95) );
generate_block( ~0, init_account_priv_key, 64 );
BOOST_CHECK_EQUAL( rsf(),
"0000000000000000000000000000000000000000000000000000000000000000"
"1111100000000000001000000001000001000100101011111111111111111111"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(31) );
generate_block( ~0, init_account_priv_key, 32 );
BOOST_CHECK_EQUAL( rsf(),
"0000000000000000000000000000000010000000000000000000000000000000"
"0000000000000000000000000000000001111100000000000001000000001000"
);
BOOST_CHECK_EQUAL( db.witness_participation_rate(), pct(8) );
}
FC_LOG_AND_RETHROW()
}
BOOST_AUTO_TEST_SUITE_END()