diff --git a/libraries/chain/assert_evaluator.cpp b/libraries/chain/assert_evaluator.cpp index f7fe1a14..c805280b 100644 --- a/libraries/chain/assert_evaluator.cpp +++ b/libraries/chain/assert_evaluator.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -38,6 +39,10 @@ struct predicate_evaluator { FC_ASSERT( p.asset_id(db).symbol == p.symbol ); } + void operator()( const block_id_predicate& p )const + { + FC_ASSERT( block_summary_id_type( block_header::num_from_id( p.id ) )(db).block_id == p.id ); + } }; void_result assert_evaluator::do_evaluate( const assert_operation& o ) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 9cccc9ff..5adba8a5 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -547,11 +547,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx ref_block_height = uint32_t( x0 ); } - const block_summary_object& tapos_block_summary = - static_cast( - get_index() - .get(block_summary_id_type(ref_block_height)) - ); + const auto& tapos_block_summary = block_summary_id_type( ref_block_height )(*this); //This is the signature check for transactions with relative expiration. if( !(skip & skip_transaction_signatures) ) @@ -561,9 +557,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx for( const auto& sig : trx.signatures ) { FC_ASSERT(eval_state._sigs.insert(std::make_pair( - public_key_type( - fc::ecc::public_key(sig, - trx.digest(tapos_block_summary.block_id))), + public_key_type( fc::ecc::public_key(sig, trx.digest())), false)).second, "Multiple signatures by same key detected"); } diff --git a/libraries/chain/include/graphene/chain/block_summary_object.hpp b/libraries/chain/include/graphene/chain/block_summary_object.hpp index ec8dcd0d..ddf44d6f 100644 --- a/libraries/chain/include/graphene/chain/block_summary_object.hpp +++ b/libraries/chain/include/graphene/chain/block_summary_object.hpp @@ -36,7 +36,7 @@ namespace graphene { namespace chain { static const uint8_t space_id = implementation_ids; static const uint8_t type_id = impl_block_summary_object_type; - block_id_type block_id; + block_id_type block_id; fc::time_point_sec timestamp; }; diff --git a/libraries/chain/include/graphene/chain/protocol/assert.hpp b/libraries/chain/include/graphene/chain/protocol/assert.hpp index 2177df87..48a9db77 100644 --- a/libraries/chain/include/graphene/chain/protocol/assert.hpp +++ b/libraries/chain/include/graphene/chain/protocol/assert.hpp @@ -34,13 +34,27 @@ namespace graphene { namespace chain { }; + /** + * Used to verify that a specific block is part of the + * blockchain history. This helps protect some high-value + * transactions to newly created IDs + * + * The block ID must be within the last 2^16 blocks. + */ + struct block_id_predicate + { + block_id_type id; + bool validate()const{ return true; } + }; + /** * When defining predicates do not make the protocol dependent upon * implementation details. */ typedef static_variant< account_name_eq_lit_predicate, - asset_symbol_eq_lit_predicate + asset_symbol_eq_lit_predicate, + block_id_predicate > predicate; @@ -71,5 +85,7 @@ namespace graphene { namespace chain { FC_REFLECT( graphene::chain::assert_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::account_name_eq_lit_predicate, (account_id)(name) ) FC_REFLECT( graphene::chain::asset_symbol_eq_lit_predicate, (asset_id)(symbol) ) +FC_REFLECT( graphene::chain::block_id_predicate, (id) ) FC_REFLECT_TYPENAME( graphene::chain::predicate ) FC_REFLECT( graphene::chain::assert_operation, (fee)(fee_paying_account)(predicates)(required_auths)(extensions) ) + diff --git a/libraries/chain/include/graphene/chain/protocol/transaction.hpp b/libraries/chain/include/graphene/chain/protocol/transaction.hpp index 4575742e..776bf162 100644 --- a/libraries/chain/include/graphene/chain/protocol/transaction.hpp +++ b/libraries/chain/include/graphene/chain/protocol/transaction.hpp @@ -89,13 +89,10 @@ namespace graphene { namespace chain { vector operations; extensions_type extensions; - /// Calculate the digest for a transaction with a reference block - /// @param ref_block_id Full block ID of the reference block - digest_type digest(const block_id_type& ref_block_id)const; /// Calculate the digest for a transaction with an absolute expiration time - digest_type digest()const; + digest_type digest()const; transaction_id_type id()const; - void validate() const; + void validate() const; void set_expiration( fc::time_point_sec expiration_time ); void set_expiration( const block_id_type& reference_block, unsigned_int lifetime_intervals = 3 ); @@ -115,10 +112,6 @@ namespace graphene { namespace chain { } void get_required_authorities( flat_set& active, flat_set& owner, vector& other )const; - - protected: - // Intentionally unreflected: does not go on wire - optional block_id_cache; }; /** @@ -135,6 +128,14 @@ namespace graphene { namespace chain { /** returns signature but does not append */ signature_type sign( const private_key_type& key )const; + /** + * The purpose of this method is to identify the minimal subset of @ref available_keys that are + * required to sign + */ + set get_required_signatures( const set& available_keys, + const map& active_authorities, + const map& owner_authorities )const; + /** * Given a set of private keys sign this transaction with a minimial subset of required keys. * diff --git a/libraries/chain/protocol/transaction.cpp b/libraries/chain/protocol/transaction.cpp index 5dc32798..9a02a98a 100644 --- a/libraries/chain/protocol/transaction.cpp +++ b/libraries/chain/protocol/transaction.cpp @@ -23,13 +23,6 @@ namespace graphene { namespace chain { -digest_type transaction::digest(const block_id_type& ref_block_id) const -{ - digest_type::encoder enc; - fc::raw::pack( enc, ref_block_id ); - fc::raw::pack( enc, *this ); - return enc.result(); -} digest_type processed_transaction::merkle_digest()const { @@ -38,8 +31,6 @@ digest_type processed_transaction::merkle_digest()const digest_type transaction::digest()const { - //Only use this digest() for transactions with absolute expiration times. - assert(relative_expiration == 0); digest_type::encoder enc; fc::raw::pack( enc, *this ); return enc.result(); @@ -65,24 +56,11 @@ graphene::chain::transaction_id_type graphene::chain::transaction::id() const const signature_type& graphene::chain::signed_transaction::sign(const private_key_type& key) { - if( relative_expiration != 0 ) - { - // Relative expiration is set, meaning we must include the block ID in the signature - FC_ASSERT(block_id_cache.valid()); - signatures.push_back(key.sign_compact(digest(*block_id_cache))); - } else { - signatures.push_back(key.sign_compact(digest())); - } + signatures.push_back(key.sign_compact(digest())); return signatures.back(); } signature_type graphene::chain::signed_transaction::sign(const private_key_type& key)const { - if( relative_expiration != 0 ) - { - // Relative expiration is set, meaning we must include the block ID in the signature - FC_ASSERT(block_id_cache.valid()); - return key.sign_compact(digest(*block_id_cache)); - } return key.sign_compact(digest()); } @@ -91,7 +69,6 @@ void transaction::set_expiration( fc::time_point_sec expiration_time ) ref_block_num = 0; relative_expiration = 0; ref_block_prefix = expiration_time.sec_since_epoch(); - block_id_cache.reset(); } void transaction::set_expiration( const block_id_type& reference_block, unsigned_int lifetime_intervals ) @@ -99,8 +76,8 @@ void transaction::set_expiration( const block_id_type& reference_block, unsigned ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]); ref_block_prefix = reference_block._hash[1]; relative_expiration = lifetime_intervals; - block_id_cache = reference_block; } + void transaction::get_required_authorities( flat_set& active, flat_set& owner, vector& other )const { for( const auto& op : operations )