Restore secret hashes from witnesses -- this is a selective restore of the parts of commits 59a3ca32b7 and c2e5432a30 that generated the secret hashes (it omits the changes to the witness scheduling algorithm)
This commit is contained in:
parent
da43a8712d
commit
9b101cefcf
16 changed files with 194 additions and 5 deletions
|
|
@ -23,7 +23,7 @@ endif()
|
|||
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules" )
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS "ON")
|
||||
set(GRAPHENE_EGENESIS_JSON "${CMAKE_CURRENT_SOURCE_DIR}/genesis.json" )
|
||||
set(GRAPHENE_EGENESIS_JSON "${CMAKE_CURRENT_SOURCE_DIR}/genesis.json" CACHE PATH "location of the genesis.json to embed in the executable" )
|
||||
|
||||
#set (ENABLE_INSTALLER 1)
|
||||
#set (USE_PCH 1)
|
||||
|
|
|
|||
|
|
@ -394,6 +394,22 @@ signed_block database::_generate_block(
|
|||
pending_block.transaction_merkle_root = pending_block.calculate_merkle_root();
|
||||
pending_block.witness = witness_id;
|
||||
|
||||
// Genesis witnesses start with a default initial secret
|
||||
if( witness_obj.next_secret_hash == secret_hash_type::hash( secret_hash_type() ) )
|
||||
pending_block.previous_secret = secret_hash_type();
|
||||
else
|
||||
{
|
||||
secret_hash_type::encoder last_enc;
|
||||
fc::raw::pack( last_enc, block_signing_private_key );
|
||||
fc::raw::pack( last_enc, witness_obj.previous_secret );
|
||||
pending_block.previous_secret = last_enc.result();
|
||||
}
|
||||
|
||||
secret_hash_type::encoder next_enc;
|
||||
fc::raw::pack( next_enc, block_signing_private_key );
|
||||
fc::raw::pack( next_enc, pending_block.previous_secret );
|
||||
pending_block.next_secret_hash = secret_hash_type::hash(next_enc.result());
|
||||
|
||||
if( !(skip & skip_witness_signature) )
|
||||
pending_block.sign( block_signing_private_key );
|
||||
|
||||
|
|
@ -662,6 +678,8 @@ const witness_object& database::validate_block_header( uint32_t skip, const sign
|
|||
FC_ASSERT( head_block_id() == next_block.previous, "", ("head_block_id",head_block_id())("next.prev",next_block.previous) );
|
||||
FC_ASSERT( head_block_time() < next_block.timestamp, "", ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()) );
|
||||
const witness_object& witness = next_block.witness(*this);
|
||||
FC_ASSERT( secret_hash_type::hash( next_block.previous_secret ) == witness.next_secret_hash, "",
|
||||
("previous_secret", next_block.previous_secret)("next_secret_hash", witness.next_secret_hash)("null_secret_hash", secret_hash_type::hash( secret_hash_type())));
|
||||
|
||||
if( !(skip&skip_witness_signature) )
|
||||
FC_ASSERT( next_block.validate_signee( witness.signing_key ) );
|
||||
|
|
|
|||
|
|
@ -623,6 +623,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(),
|
||||
[&](const genesis_state_type::initial_witness_type& witness) {
|
||||
witness_create_operation op;
|
||||
op.initial_secret = secret_hash_type::hash(secret_hash_type());
|
||||
op.witness_account = get_account_id(witness.owner_name);
|
||||
op.block_signing_key = witness.block_signing_key;
|
||||
apply_operation(genesis_eval_state, op);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ void database::update_global_dynamic_data( const signed_block& b )
|
|||
|
||||
// dynamic global properties updating
|
||||
modify( _dgp, [&]( dynamic_global_property_object& dgp ){
|
||||
secret_hash_type::encoder enc;
|
||||
fc::raw::pack( enc, dgp.random );
|
||||
fc::raw::pack( enc, b.previous_secret );
|
||||
dgp.random = enc.result();
|
||||
|
||||
if( BOOST_UNLIKELY( b.block_num() == 1 ) )
|
||||
dgp.recently_missed_count = 0;
|
||||
else if( _checkpoints.size() && _checkpoints.rbegin()->first >= b.block_num() )
|
||||
|
|
@ -118,6 +123,8 @@ void database::update_signing_witness(const witness_object& signing_witness, con
|
|||
{
|
||||
_wit.last_aslot = new_block_aslot;
|
||||
_wit.last_confirmed_block_num = new_block.block_num();
|
||||
_wit.previous_secret = new_block.previous_secret;
|
||||
_wit.next_secret_hash = new_block.next_secret_hash;
|
||||
} );
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +506,7 @@ void database::update_tournaments()
|
|||
*start_iter->start_time <= head_block_time())
|
||||
{
|
||||
modify(*start_iter, [&](tournament_object& t) {
|
||||
t.on_start_time_arrived();
|
||||
t.on_start_time_arrived(*this);
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ fc::variant_object get_config()
|
|||
result[ "GRAPHENE_MAX_URL_LENGTH" ] = GRAPHENE_MAX_URL_LENGTH;
|
||||
result[ "GRAPHENE_NEAR_SCHEDULE_CTR_IV" ] = GRAPHENE_NEAR_SCHEDULE_CTR_IV;
|
||||
result[ "GRAPHENE_FAR_SCHEDULE_CTR_IV" ] = GRAPHENE_FAR_SCHEDULE_CTR_IV;
|
||||
result[ "GRAPHENE_RNG_SEED_LENGTH" ] = GRAPHENE_RNG_SEED_LENGTH;
|
||||
result[ "GRAPHENE_CORE_ASSET_CYCLE_RATE" ] = GRAPHENE_CORE_ASSET_CYCLE_RATE;
|
||||
result[ "GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS" ] = GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS;
|
||||
result[ "GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK" ] = GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK;
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@
|
|||
| (uint64_t( 0x84ca ) << 0x10) \
|
||||
| (uint64_t( 0xa73b ) ) )
|
||||
|
||||
// counter used to determine bits of entropy
|
||||
// must be less than or equal to secret_hash_type::data_length()
|
||||
#define GRAPHENE_RNG_SEED_LENGTH (160 / 8)
|
||||
|
||||
/**
|
||||
* every second, the fraction of burned core asset which cycles is
|
||||
* GRAPHENE_CORE_ASSET_CYCLE_RATE / (1 << GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ namespace graphene { namespace chain {
|
|||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_dynamic_global_property_object_type;
|
||||
|
||||
secret_hash_type random;
|
||||
uint32_t head_block_number = 0;
|
||||
block_id_type head_block_id;
|
||||
time_point_sec time;
|
||||
|
|
@ -125,6 +126,7 @@ namespace graphene { namespace chain {
|
|||
}}
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene::db::object),
|
||||
(random)
|
||||
(head_block_number)
|
||||
(head_block_id)
|
||||
(time)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ namespace graphene { namespace chain {
|
|||
uint32_t block_num()const { return num_from_id(previous) + 1; }
|
||||
fc::time_point_sec timestamp;
|
||||
witness_id_type witness;
|
||||
secret_hash_type next_secret_hash;
|
||||
secret_hash_type previous_secret;
|
||||
checksum_type transaction_merkle_root;
|
||||
extensions_type extensions;
|
||||
|
||||
|
|
@ -57,6 +59,13 @@ namespace graphene { namespace chain {
|
|||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::block_header, (previous)(timestamp)(witness)(transaction_merkle_root)(extensions) )
|
||||
FC_REFLECT( graphene::chain::block_header,
|
||||
(previous)
|
||||
(timestamp)
|
||||
(witness)
|
||||
(next_secret_hash)
|
||||
(previous_secret)
|
||||
(transaction_merkle_root)
|
||||
(extensions) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::signed_block_header, (graphene::chain::block_header), (witness_signature) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::signed_block, (graphene::chain::signed_block_header), (transactions) )
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ namespace graphene { namespace chain {
|
|||
typedef fc::sha256 digest_type;
|
||||
typedef fc::ecc::compact_signature signature_type;
|
||||
typedef safe<int64_t> share_type;
|
||||
typedef fc::ripemd160 secret_hash_type;
|
||||
typedef uint16_t weight_type;
|
||||
|
||||
struct public_key_type
|
||||
|
|
@ -353,6 +354,8 @@ FC_REFLECT_ENUM( graphene::chain::object_type,
|
|||
(worker_object_type)
|
||||
(balance_object_type)
|
||||
(tournament_object_type)
|
||||
(match_object_type)
|
||||
(game_object_type)
|
||||
(OBJECT_TYPE_COUNT)
|
||||
)
|
||||
FC_REFLECT_ENUM( graphene::chain::impl_object_type,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace graphene { namespace chain {
|
|||
account_id_type witness_account;
|
||||
string url;
|
||||
public_key_type block_signing_key;
|
||||
secret_hash_type initial_secret;
|
||||
|
||||
account_id_type fee_payer()const { return witness_account; }
|
||||
void validate()const;
|
||||
|
|
@ -77,7 +78,7 @@ namespace graphene { namespace chain {
|
|||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::witness_create_operation::fee_parameters_type, (fee) )
|
||||
FC_REFLECT( graphene::chain::witness_create_operation, (fee)(witness_account)(url)(block_signing_key) )
|
||||
FC_REFLECT( graphene::chain::witness_create_operation, (fee)(witness_account)(url)(block_signing_key)(initial_secret) )
|
||||
|
||||
FC_REFLECT( graphene::chain::witness_update_operation::fee_parameters_type, (fee) )
|
||||
FC_REFLECT( graphene::chain::witness_update_operation, (fee)(witness)(witness_account)(new_url)(new_signing_key) )
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace graphene { namespace chain {
|
|||
/// called by database maintenance code when registration for this contest has expired
|
||||
void on_registration_deadline_passed(database& db);
|
||||
void on_player_registered(database& db, account_id_type payer_id, account_id_type player_id);
|
||||
void on_start_time_arrived();
|
||||
void on_start_time_arrived(database& db);
|
||||
void on_final_game_completed();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ namespace graphene { namespace chain {
|
|||
account_id_type witness_account;
|
||||
uint64_t last_aslot = 0;
|
||||
public_key_type signing_key;
|
||||
secret_hash_type next_secret_hash;
|
||||
secret_hash_type previous_secret;
|
||||
optional< vesting_balance_id_type > pay_vb;
|
||||
vote_id_type vote_id;
|
||||
uint64_t total_votes = 0;
|
||||
|
|
@ -74,6 +76,8 @@ FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object),
|
|||
(witness_account)
|
||||
(last_aslot)
|
||||
(signing_key)
|
||||
(next_secret_hash)
|
||||
(previous_secret)
|
||||
(pay_vb)
|
||||
(vote_id)
|
||||
(total_votes)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ object_id_type witness_create_evaluator::do_apply( const witness_create_operatio
|
|||
const auto& new_witness_object = db().create<witness_object>( [&]( witness_object& obj ){
|
||||
obj.witness_account = op.witness_account;
|
||||
obj.signing_key = op.block_signing_key;
|
||||
obj.next_secret_hash = op.initial_secret;
|
||||
obj.vote_id = vote_id;
|
||||
obj.url = op.url;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -514,6 +514,7 @@ public:
|
|||
result["participation"] = (100*dynamic_props.recent_slots_filled.popcount()) / 128.0;
|
||||
result["active_witnesses"] = global_props.active_witnesses;
|
||||
result["active_committee_members"] = global_props.active_committee_members;
|
||||
result["entropy"] = dynamic_props.random;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1453,6 +1454,10 @@ public:
|
|||
witness_create_op.witness_account = witness_account.id;
|
||||
witness_create_op.block_signing_key = witness_public_key;
|
||||
witness_create_op.url = url;
|
||||
secret_hash_type::encoder enc;
|
||||
fc::raw::pack(enc, witness_private_key);
|
||||
fc::raw::pack(enc, secret_hash_type());
|
||||
witness_create_op.initial_secret = secret_hash_type::hash(enc.result());
|
||||
|
||||
if (_remote_db->get_witness_by_account(witness_create_op.witness_account))
|
||||
FC_THROW("Account ${owner_account} is already a witness", ("owner_account", owner_account));
|
||||
|
|
|
|||
|
|
@ -655,6 +655,10 @@ const witness_object& database_fixture::create_witness( const account_object& ow
|
|||
witness_create_operation op;
|
||||
op.witness_account = owner.id;
|
||||
op.block_signing_key = signing_private_key.get_public_key();
|
||||
secret_hash_type::encoder enc;
|
||||
fc::raw::pack(enc, signing_private_key);
|
||||
fc::raw::pack(enc, secret_hash_type());
|
||||
op.initial_secret = secret_hash_type::hash(enc.result());
|
||||
trx.operations.push_back(op);
|
||||
trx.validate();
|
||||
processed_transaction ptx = db.push_transaction(trx, ~0);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include <fc/crypto/digest.hpp>
|
||||
#include <fc/crypto/hex.hpp>
|
||||
#include <fc/crypto/hash_ctr_rng.hpp>
|
||||
#include "../common/database_fixture.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
|
@ -197,6 +198,134 @@ BOOST_AUTO_TEST_CASE( memo_test )
|
|||
BOOST_CHECK_EQUAL(m.get_message(receiver, sender.get_public_key()), "Hello, world!");
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
BOOST_AUTO_TEST_CASE( witness_rng_test_bits )
|
||||
{
|
||||
try
|
||||
{
|
||||
const uint64_t COUNT = 131072;
|
||||
const uint64_t HASH_SIZE = 32;
|
||||
string ref_bits = "";
|
||||
ref_bits.reserve( COUNT * HASH_SIZE );
|
||||
static const char seed_data[] = "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55";
|
||||
|
||||
for( uint64_t i=0; i<COUNT; i++ )
|
||||
{
|
||||
// grab the bits
|
||||
fc::sha256::encoder enc;
|
||||
enc.write( seed_data, HASH_SIZE );
|
||||
enc.put( char((i ) & 0xFF) );
|
||||
enc.put( char((i >> 0x08) & 0xFF) );
|
||||
enc.put( char((i >> 0x10) & 0xFF) );
|
||||
enc.put( char((i >> 0x18) & 0xFF) );
|
||||
enc.put( char((i >> 0x20) & 0xFF) );
|
||||
enc.put( char((i >> 0x28) & 0xFF) );
|
||||
enc.put( char((i >> 0x30) & 0xFF) );
|
||||
enc.put( char((i >> 0x38) & 0xFF) );
|
||||
|
||||
fc::sha256 result = enc.result();
|
||||
auto result_data = result.data();
|
||||
std::copy( result_data, result_data+HASH_SIZE, std::back_inserter( ref_bits ) );
|
||||
}
|
||||
|
||||
fc::sha256 seed = fc::sha256::hash( string("") );
|
||||
// seed = sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
BOOST_CHECK( memcmp( seed.data(), seed_data, HASH_SIZE ) == 0 );
|
||||
|
||||
fc::hash_ctr_rng<fc::sha256, 32> test_rng(seed.data(), 0);
|
||||
// python2 -c 'import hashlib; import struct; h = lambda x : hashlib.sha256(x).digest(); i = lambda x : struct.pack("<Q", x); print( h( h("") + i(0) ) )' | hd
|
||||
string ref_bits_hex =
|
||||
"5c5d42dcf39f71c0226ca720d8d518db615b5773f038e5e491963f6f47621bbd" // h( h("") + i(0) )
|
||||
"43fd6dae047c400060be262e6d443200eacd1fafcb77828638085c2e2341fd8d" // h( h("") + i(1) )
|
||||
"d666330a7441dc7279b786e65aba32817275989cfc691b3901f000fb0f14cd05" // h( h("") + i(2) )
|
||||
"34bd93f83d7bac4a667d62fee39bd5eb1991fbadc29a5f216ea746772ca31544" // h( h("") + i(3) )
|
||||
"d3b41a093eab01cd25f987a909b2f4812b0f38475e0fe40f6f42a12c6e018aa7" // ...
|
||||
"c8db17b946c5a6bceaa7b903c93e6ccb8cc6c09b0cfd2108d930de1a79c3a68e"
|
||||
"cc1945b36c82e356b6d127057d036a150cb03b760e9c9e706c560f32a749e80d"
|
||||
"872b28fe97e289d4f6f361f3427d454113e3b513892d129398dac4daf8a0e43e"
|
||||
"8d7a5a2f3cbb245fa471e87e30a38d9c775c985c28db6e521e34cf1e88507c26"
|
||||
"c662f230eed0f10899c3a74a2d1bfb88d732909b206a2aed3ae0bda728fac8fe"
|
||||
"38eface8b1d473e45cbb40603bcef8bf2219e55669c7a2cfb5f8d52610689f14"
|
||||
"3b1d1734273b069a7de7cc6dd2e80db09d1feff200c9bdaf033cd553ea40e05d"
|
||||
"16653ca7aa7f790a95c6a8d41e5694b0c6bff806c3ce3e0e320253d408fb6f27"
|
||||
"b55df71d265de0b86a1cdf45d1d9c53da8ebf0ceec136affa12228d0d372e698"
|
||||
"37e9305ce57d386d587039b49b67104fd4d8467e87546237afc9a90cf8c677f9"
|
||||
"fc26784c94f754cf7aeacb6189e705e2f1873ea112940560f11dbbebb22a8922"
|
||||
;
|
||||
char* ref_bits_chars = new char[ ref_bits_hex.length() / 2 ];
|
||||
fc::from_hex( ref_bits_hex, ref_bits_chars, ref_bits_hex.length() / 2 );
|
||||
string ref_bits_str( ref_bits_chars, ref_bits_hex.length() / 2 );
|
||||
delete[] ref_bits_chars;
|
||||
ref_bits_chars = nullptr;
|
||||
|
||||
BOOST_CHECK( ref_bits_str.length() < ref_bits.length() );
|
||||
BOOST_CHECK( ref_bits_str == ref_bits.substr( 0, ref_bits_str.length() ) );
|
||||
//std::cout << "ref_bits_str: " << fc::to_hex( ref_bits_str.c_str(), std::min( ref_bits_str.length(), size_t(256) ) ) << "\n";
|
||||
//std::cout << "ref_bits : " << fc::to_hex( ref_bits .c_str(), std::min( ref_bits.length(), size_t(256) ) ) << "\n";
|
||||
|
||||
// when we get to this point, our code to generate the RNG byte output is working.
|
||||
// now let's test get_bits() as follows:
|
||||
|
||||
uint64_t ref_get_bits_offset = 0;
|
||||
|
||||
auto ref_get_bits = [&]( uint8_t count ) -> uint64_t
|
||||
{
|
||||
uint64_t result = 0;
|
||||
uint64_t i = ref_get_bits_offset;
|
||||
uint64_t mask = 1;
|
||||
while( count > 0 )
|
||||
{
|
||||
if( ref_bits[ i >> 3 ] & (1 << (i & 7)) )
|
||||
result |= mask;
|
||||
mask += mask;
|
||||
i++;
|
||||
count--;
|
||||
}
|
||||
ref_get_bits_offset = i;
|
||||
return result;
|
||||
};
|
||||
|
||||
// use PRNG to decide between 0-64 bits
|
||||
std::minstd_rand rng;
|
||||
rng.seed( 9999 );
|
||||
std::uniform_int_distribution< uint16_t > bit_dist( 0, 64 );
|
||||
for( int i=0; i<10000; i++ )
|
||||
{
|
||||
uint8_t bit_count = bit_dist( rng );
|
||||
uint64_t ref_bits = ref_get_bits( bit_count );
|
||||
uint64_t test_bits = test_rng.get_bits( bit_count );
|
||||
//std::cout << i << ": get(" << int(bit_count) << ") -> " << test_bits << " (expect " << ref_bits << ")\n";
|
||||
if( bit_count < 64 )
|
||||
{
|
||||
BOOST_CHECK( ref_bits < (uint64_t( 1 ) << bit_count ) );
|
||||
BOOST_CHECK( test_bits < (uint64_t( 1 ) << bit_count ) );
|
||||
}
|
||||
BOOST_CHECK( ref_bits == test_bits );
|
||||
if( ref_bits != test_bits )
|
||||
break;
|
||||
}
|
||||
|
||||
std::uniform_int_distribution< uint64_t > whole_dist(
|
||||
0, std::numeric_limits<uint64_t>::max() );
|
||||
for( int i=0; i<10000; i++ )
|
||||
{
|
||||
uint8_t bit_count = bit_dist( rng );
|
||||
uint64_t bound = whole_dist( rng ) & ((uint64_t(1) << bit_count) - 1);
|
||||
//std::cout << "bound:" << bound << "\n";
|
||||
uint64_t rnum = test_rng( bound );
|
||||
//std::cout << "rnum:" << rnum << "\n";
|
||||
if( bound > 1 )
|
||||
{
|
||||
BOOST_CHECK( rnum < bound );
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK( rnum == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( exceptions )
|
||||
{
|
||||
GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(balance_claim_invalid_claim_amount, "Etc"), balance_claim_invalid_claim_amount);
|
||||
|
|
|
|||
Loading…
Reference in a new issue