未验证 提交 e12abf3f 编写于 作者: W wanderingbort 提交者: GitHub

Merge pull request #6494 from EOSIO/packed-txn

packed_transaction enhancement
......@@ -8,7 +8,7 @@
namespace eosio { namespace chain {
void chain_id_type::reflector_verify()const {
void chain_id_type::reflector_init()const {
EOS_ASSERT( *reinterpret_cast<const fc::sha256*>(this) != fc::sha256(), chain_id_type_exception, "chain_id_type cannot be zero" );
}
......
......@@ -1009,7 +1009,8 @@ struct controller_impl {
}
}
transaction_context trx_context(self, trx->trx, trx->id, start);
const signed_transaction& trn = trx->packed_trx->get_signed_transaction();
transaction_context trx_context(self, trn, trx->id, start);
if ((bool)subjective_cpu_leeway && pending->_block_status == controller::block_status::incomplete) {
trx_context.leeway = *subjective_cpu_leeway;
}
......@@ -1022,17 +1023,17 @@ struct controller_impl {
trx_context.init_for_implicit_trx();
trx_context.enforce_whiteblacklist = false;
} else {
bool skip_recording = replay_head_time && (time_point(trx->trx.expiration) <= *replay_head_time);
bool skip_recording = replay_head_time && (time_point(trn.expiration) <= *replay_head_time);
trx_context.init_for_input_trx( trx->packed_trx->get_unprunable_size(),
trx->packed_trx->get_prunable_size(),
skip_recording);
}
trx_context.delay = fc::seconds(trx->trx.delay_sec);
trx_context.delay = fc::seconds(trn.delay_sec);
if( !self.skip_auth_check() && !trx->implicit ) {
authorization.check_authorization(
trx->trx.actions,
trn.actions,
trx->recover_keys( chain_id ),
{},
trx_context.delay,
......
......@@ -583,27 +583,36 @@ namespace impl {
from_variant(vo["compression"], compression);
bytes packed_cfd;
std::vector<bytes> cfd;
bool use_packed_cfd = false;
if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) {
from_variant(vo["packed_context_free_data"], packed_cfd );
use_packed_cfd = true;
} else if( vo.contains("context_free_data") ) {
from_variant(vo["context_free_data"], cfd);
}
if( vo.contains("packed_trx") && vo["packed_trx"].is_string() && !vo["packed_trx"].as_string().empty() ) {
bytes packed_trx;
std::vector<bytes> cfd;
from_variant(vo["packed_trx"], packed_trx);
if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) {
from_variant(vo["packed_context_free_data"], packed_cfd );
} else if( vo.contains("context_free_data") ) {
from_variant(vo["context_free_data"], cfd);
if( use_packed_cfd ) {
ptrx = packed_transaction( std::move( packed_trx ), std::move( signatures ), std::move( packed_cfd ), compression );
} else {
ptrx = packed_transaction( std::move( packed_trx ), std::move( signatures ), std::move( cfd ), compression );
}
ptrx = packed_transaction( std::move(packed_trx), std::move(signatures), std::move(packed_cfd), std::move(cfd), compression );
} else {
EOS_ASSERT(vo.contains("transaction"), packed_transaction_type_exception, "Missing transaction");
signed_transaction trx;
trx.signatures = std::move(signatures);
extract(vo["transaction"], trx, resolver, ctx);
if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) {
from_variant(vo["packed_context_free_data"], packed_cfd );
} else if( vo.contains("context_free_data") ) {
from_variant(vo["context_free_data"], trx.context_free_data );
if( use_packed_cfd ) {
transaction trx;
extract( vo["transaction"], trx, resolver, ctx );
ptrx = packed_transaction( std::move(trx), std::move(signatures), std::move(packed_cfd), compression );
} else {
signed_transaction trx;
extract( vo["transaction"], trx, resolver, ctx );
trx.signatures = std::move( signatures );
trx.context_free_data = std::move(cfd);
ptrx = packed_transaction( std::move( trx ), compression );
}
ptrx = packed_transaction( std::move(trx), std::move(packed_cfd), compression );
}
}
};
......@@ -616,11 +625,11 @@ namespace impl {
* @tparam Reslover - callable with the signature (const name& code_account) -> optional<abi_def>
*/
template<typename T, typename Resolver>
class abi_from_variant_visitor : reflector_verifier_visitor<T>
class abi_from_variant_visitor : reflector_init_visitor<T>
{
public:
abi_from_variant_visitor( const variant_object& _vo, T& v, Resolver _resolver, abi_traverse_context& _ctx )
: reflector_verifier_visitor<T>(v)
: reflector_init_visitor<T>(v)
,_vo(_vo)
,_resolver(_resolver)
,_ctx(_ctx)
......
......@@ -84,7 +84,7 @@ struct asset
friend struct fc::reflector<asset>;
void reflector_verify()const {
void reflector_init()const {
EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" );
EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" );
}
......
......@@ -34,7 +34,7 @@ namespace chain {
return ds;
}
void reflector_verify()const;
void reflector_init()const;
private:
chain_id_type() = default;
......
......@@ -137,7 +137,7 @@ namespace eosio {
return ds << s.to_string();
}
void reflector_verify()const {
void reflector_init()const {
EOS_ASSERT( decimals() <= max_precision, symbol_type_exception, "precision ${p} should be <= 18", ("p", decimals()) );
EOS_ASSERT( valid_name(name()), symbol_type_exception, "invalid symbol: ${name}", ("name",name()));
}
......
......@@ -85,8 +85,12 @@ namespace eosio { namespace chain {
: transaction(std::move(trx))
, signatures(signatures)
, context_free_data(context_free_data)
{
}
{}
signed_transaction( transaction&& trx, const vector<signature_type>& signatures, vector<bytes>&& context_free_data)
: transaction(std::move(trx))
, signatures(signatures)
, context_free_data(std::move(context_free_data))
{}
vector<signature_type> signatures;
vector<bytes> context_free_data; ///< for each context-free action, there is an entry here
......@@ -111,48 +115,50 @@ namespace eosio { namespace chain {
packed_transaction& operator=(packed_transaction&&) = default;
explicit packed_transaction(const signed_transaction& t, compression_type _compression = none)
:signatures(t.signatures), compression(_compression)
:signatures(t.signatures), compression(_compression), unpacked_trx(t)
{
set_transaction(t);
set_context_free_data(t.context_free_data);
local_pack_transaction();
local_pack_context_free_data();
}
explicit packed_transaction(signed_transaction&& t, compression_type _compression = none)
:signatures(std::move(t.signatures)), compression(_compression)
:signatures(t.signatures), compression(_compression), unpacked_trx(std::move(t))
{
set_transaction(t);
set_context_free_data(t.context_free_data);
local_pack_transaction();
local_pack_context_free_data();
}
// used by abi_serializer
explicit packed_transaction( bytes&& packed_txn, vector<signature_type>&& sigs,
bytes&& packed_cfd, vector<bytes>&& cfd, compression_type _compression );
explicit packed_transaction( signed_transaction&& t, bytes&& packed_cfd, compression_type _compression );
packed_transaction( bytes&& packed_txn, vector<signature_type>&& sigs, bytes&& packed_cfd, compression_type _compression );
packed_transaction( bytes&& packed_txn, vector<signature_type>&& sigs, vector<bytes>&& cfd, compression_type _compression );
packed_transaction( transaction&& t, vector<signature_type>&& sigs, bytes&& packed_cfd, compression_type _compression );
uint32_t get_unprunable_size()const;
uint32_t get_prunable_size()const;
digest_type packed_digest()const;
time_point_sec expiration()const;
transaction_id_type id()const;
transaction_id_type get_uncached_id()const; // thread safe
bytes get_raw_transaction()const; // thread safe
vector<bytes> get_context_free_data()const;
transaction get_transaction()const;
signed_transaction get_signed_transaction()const;
transaction_id_type id()const { return unpacked_trx.id(); }
bytes get_raw_transaction()const;
time_point_sec expiration()const { return unpacked_trx.expiration; }
const vector<bytes>& get_context_free_data()const { return unpacked_trx.context_free_data; }
const transaction& get_transaction()const { return unpacked_trx; }
const signed_transaction& get_signed_transaction()const { return unpacked_trx; }
const vector<signature_type>& get_signatures()const { return signatures; }
const fc::enum_type<uint8_t,compression_type>& get_compression()const { return compression; }
const bytes& get_packed_context_free_data()const { return packed_context_free_data; }
const bytes& get_packed_transaction()const { return packed_trx; }
const bytes& get_packed_context_free_data()const { return packed_context_free_data; }
const bytes& get_packed_transaction()const { return packed_trx; }
private:
void local_unpack()const;
void set_transaction(const transaction& t);
void set_context_free_data(const vector<bytes>& cfd);
void local_unpack_transaction(vector<bytes>&& context_free_data);
void local_unpack_context_free_data();
void local_pack_transaction();
void local_pack_context_free_data();
friend struct fc::reflector<packed_transaction>;
friend struct fc::reflector_init_visitor<packed_transaction>;
void reflector_init();
private:
vector<signature_type> signatures;
fc::enum_type<uint8_t,compression_type> compression;
......@@ -160,7 +166,8 @@ namespace eosio { namespace chain {
bytes packed_trx;
private:
mutable optional<transaction> unpacked_trx; // <-- intermediate buffer used to retrieve values
// cache unpacked trx, for thread safety do not modify after construction
signed_transaction unpacked_trx;
};
using packed_transaction_ptr = std::shared_ptr<packed_transaction>;
......
......@@ -23,7 +23,6 @@ class transaction_metadata {
public:
transaction_id_type id;
transaction_id_type signed_id;
signed_transaction trx;
packed_transaction_ptr packed_trx;
fc::microseconds sig_cpu_usage;
optional<pair<chain_id_type, flat_set<public_key_type>>> signing_keys;
......@@ -40,13 +39,13 @@ class transaction_metadata {
transaction_metadata operator=(transaction_metadata&&) = delete;
explicit transaction_metadata( const signed_transaction& t, packed_transaction::compression_type c = packed_transaction::none )
:id(t.id()), trx(t), packed_trx(std::make_shared<packed_transaction>(t, c)) {
:id(t.id()), packed_trx(std::make_shared<packed_transaction>(t, c)) {
//raw_packed = fc::raw::pack( static_cast<const transaction&>(trx) );
signed_id = digest_type::hash(*packed_trx);
}
explicit transaction_metadata( const packed_transaction_ptr& ptrx )
:id(ptrx->id()), trx( ptrx->get_signed_transaction() ), packed_trx(ptrx) {
:id(ptrx->id()), packed_trx(ptrx) {
//raw_packed = fc::raw::pack( static_cast<const transaction&>(trx) );
signed_id = digest_type::hash(*packed_trx);
}
......@@ -54,9 +53,8 @@ class transaction_metadata {
const flat_set<public_key_type>& recover_keys( const chain_id_type& chain_id );
static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool,
const chain_id_type& chain_id, fc::microseconds timelimit );
const chain_id_type& chain_id, fc::microseconds time_limit );
uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); }
};
} } // eosio::chain
......@@ -289,127 +289,110 @@ bytes packed_transaction::get_raw_transaction() const
} FC_CAPTURE_AND_RETHROW((compression)(packed_trx))
}
vector<bytes> packed_transaction::get_context_free_data()const
packed_transaction::packed_transaction( bytes&& packed_txn, vector<signature_type>&& sigs, bytes&& packed_cfd, compression_type _compression )
:signatures(std::move(sigs))
,compression(_compression)
,packed_context_free_data(std::move(packed_cfd))
,packed_trx(std::move(packed_txn))
{
try {
switch(compression) {
case none:
return unpack_context_free_data(packed_context_free_data);
case zlib:
return zlib_decompress_context_free_data(packed_context_free_data);
default:
EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm");
}
} FC_CAPTURE_AND_RETHROW((compression)(packed_context_free_data))
local_unpack_transaction({});
if( !packed_context_free_data.empty() ) {
local_unpack_context_free_data();
}
}
time_point_sec packed_transaction::expiration()const
packed_transaction::packed_transaction( bytes&& packed_txn, vector<signature_type>&& sigs, vector<bytes>&& cfd, compression_type _compression )
:signatures(std::move(sigs))
,compression(_compression)
,packed_trx(std::move(packed_txn))
{
local_unpack();
return unpacked_trx->expiration;
local_unpack_transaction( std::move( cfd ) );
if( !unpacked_trx.context_free_data.empty() ) {
local_pack_context_free_data();
}
}
transaction_id_type packed_transaction::id()const
packed_transaction::packed_transaction( transaction&& t, vector<signature_type>&& sigs, bytes&& packed_cfd, compression_type _compression )
:signatures(std::move(sigs))
,compression(_compression)
,packed_context_free_data(std::move(packed_cfd))
,unpacked_trx(std::move(t), signatures, {})
{
local_unpack();
return get_transaction().id();
local_pack_transaction();
if( !packed_context_free_data.empty() ) {
local_unpack_context_free_data();
}
}
transaction_id_type packed_transaction::get_uncached_id()const
void packed_transaction::reflector_init()
{
const auto raw = get_raw_transaction();
return fc::raw::unpack<transaction>( raw ).id();
// called after construction, but always on the same thread and before packed_transaction passed to any other threads
static_assert(&fc::reflector_init_visitor<packed_transaction>::reflector_init, "FC with reflector_init required");
static_assert(fc::raw::has_feature_reflector_init_on_unpacked_reflected_types,
"FC unpack needs to call reflector_init otherwise unpacked_trx will not be initialized");
EOS_ASSERT( unpacked_trx.expiration == time_point_sec(), tx_decompression_error, "packed_transaction already unpacked" );
local_unpack_transaction({});
local_unpack_context_free_data();
}
void packed_transaction::local_unpack()const
void packed_transaction::local_unpack_transaction(vector<bytes>&& context_free_data)
{
if (!unpacked_trx) {
try {
switch(compression) {
try {
switch( compression ) {
case none:
unpacked_trx = unpack_transaction(packed_trx);
unpacked_trx = signed_transaction( unpack_transaction( packed_trx ), signatures, std::move(context_free_data) );
break;
case zlib:
unpacked_trx = zlib_decompress_transaction(packed_trx);
unpacked_trx = signed_transaction( zlib_decompress_transaction( packed_trx ), signatures, std::move(context_free_data) );
break;
default:
EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm");
}
} FC_CAPTURE_AND_RETHROW((compression)(packed_trx))
}
}
transaction packed_transaction::get_transaction()const
{
local_unpack();
return transaction(*unpacked_trx);
EOS_THROW( unknown_transaction_compression, "Unknown transaction compression algorithm" );
}
} FC_CAPTURE_AND_RETHROW( (compression) )
}
signed_transaction packed_transaction::get_signed_transaction() const
void packed_transaction::local_unpack_context_free_data()
{
try {
switch(compression) {
EOS_ASSERT(unpacked_trx.context_free_data.empty(), tx_decompression_error, "packed_transaction.context_free_data not empty");
switch( compression ) {
case none:
return signed_transaction(get_transaction(), signatures, unpack_context_free_data(packed_context_free_data));
unpacked_trx.context_free_data = unpack_context_free_data( packed_context_free_data );
break;
case zlib:
return signed_transaction(get_transaction(), signatures, zlib_decompress_context_free_data(packed_context_free_data));
unpacked_trx.context_free_data = zlib_decompress_context_free_data( packed_context_free_data );
break;
default:
EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm");
EOS_THROW( unknown_transaction_compression, "Unknown transaction compression algorithm" );
}
} FC_CAPTURE_AND_RETHROW((compression)(packed_trx)(packed_context_free_data))
} FC_CAPTURE_AND_RETHROW( (compression) )
}
packed_transaction::packed_transaction( bytes&& packed_txn, vector<signature_type>&& sigs,
bytes&& packed_cfd, vector<bytes>&& cfd, compression_type _compression )
:signatures(std::move(sigs))
,compression(_compression)
,packed_context_free_data(std::move(packed_cfd))
,packed_trx(std::move(packed_txn))
{
EOS_ASSERT(packed_cfd.empty() || cfd.empty(), tx_decompression_error, "Invalid packed_transaction");
if( !cfd.empty() ) {
set_context_free_data(cfd);
}
}
packed_transaction::packed_transaction( signed_transaction&& t, bytes&& packed_cfd, compression_type _compression )
:signatures(std::move(t.signatures))
,compression(_compression)
,packed_context_free_data(std::move(packed_cfd))
{
set_transaction(t);
// allow passed in packed_cfd to overwrite signed_transaction.context_free_data if provided
if( packed_context_free_data.empty() ) {
set_context_free_data(t.context_free_data);
}
}
void packed_transaction::set_transaction(const transaction& t)
void packed_transaction::local_pack_transaction()
{
try {
switch(compression) {
case none:
packed_trx = pack_transaction(t);
packed_trx = pack_transaction(unpacked_trx);
break;
case zlib:
packed_trx = zlib_compress_transaction(t);
packed_trx = zlib_compress_transaction(unpacked_trx);
break;
default:
EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm");
}
} FC_CAPTURE_AND_RETHROW((compression)(t))
} FC_CAPTURE_AND_RETHROW((compression))
}
void packed_transaction::set_context_free_data(const vector<bytes>& cfd)
void packed_transaction::local_pack_context_free_data()
{
try {
switch(compression) {
case none:
packed_context_free_data = pack_context_free_data(cfd);
packed_context_free_data = pack_context_free_data(unpacked_trx.context_free_data);
break;
case zlib:
packed_context_free_data = zlib_compress_context_free_data(cfd);
packed_context_free_data = zlib_compress_context_free_data(unpacked_trx.context_free_data);
break;
default:
EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm");
......
......@@ -17,7 +17,7 @@ const flat_set<public_key_type>& transaction_metadata::recover_keys( const chain
}
}
flat_set<public_key_type> recovered_pub_keys;
sig_cpu_usage = trx.get_signature_keys( chain_id, fc::time_point::maximum(), recovered_pub_keys );
sig_cpu_usage = packed_trx->get_signed_transaction().get_signature_keys( chain_id, fc::time_point::maximum(), recovered_pub_keys );
signing_keys.emplace( chain_id, std::move( recovered_pub_keys ));
}
return signing_keys->second;
......@@ -36,7 +36,8 @@ void transaction_metadata::create_signing_keys_future( const transaction_metadat
fc::microseconds cpu_usage;
flat_set<public_key_type> recovered_pub_keys;
if( mtrx ) {
cpu_usage = mtrx->trx.get_signature_keys( chain_id, deadline, recovered_pub_keys );
const signed_transaction& trn = mtrx->packed_trx->get_signed_transaction();
cpu_usage = trn.get_signature_keys( chain_id, deadline, recovered_pub_keys );
}
return std::make_tuple( chain_id, cpu_usage, std::move( recovered_pub_keys ));
} );
......
Subproject commit a8613d3786cddfcc336808d2b9b7df655e6cc6d1
Subproject commit a6bbb25c3d395b8ccc62314311822db89569eb9d
......@@ -441,7 +441,7 @@ namespace eosio {
if( itr != _transaction_status.end() ) {
if( !itr->known_by_peer() ) {
_transaction_status.modify( itr, [&]( auto& stat ) {
stat.expired = std::min<fc::time_point>( fc::time_point::now() + fc::seconds(5), t->trx.expiration );
stat.expired = std::min<fc::time_point>( fc::time_point::now() + fc::seconds(5), t->packed_trx->expiration() );
});
}
return;
......@@ -555,8 +555,7 @@ namespace eosio {
for( const auto& receipt : s->block->transactions ) {
if( receipt.trx.which() == 1 ) {
const auto& pt = receipt.trx.get<packed_transaction>();
// get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state
const auto& tid = pt.get_uncached_id();
const auto& tid = pt.id();
auto itr = _transaction_status.find( tid );
if( itr != _transaction_status.end() )
_transaction_status.erase(itr);
......@@ -1014,8 +1013,7 @@ namespace eosio {
for( const auto& receipt : b->transactions ) {
if( receipt.trx.which() == 1 ) {
const auto& pt = receipt.trx.get<packed_transaction>();
// get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state
const auto& id = pt.get_uncached_id();
const auto& id = pt.id();
mark_transaction_known_by_peer(id);
}
}
......@@ -1552,8 +1550,7 @@ namespace eosio {
// ilog( "recv trx ${n}", ("n", id) );
if( p->expiration() < fc::time_point::now() ) return;
// get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state
const auto& id = p->get_uncached_id();
const auto& id = p->id();
if( mark_transaction_known_by_peer( id ) )
return;
......
......@@ -734,7 +734,7 @@ void mongo_db_plugin_impl::_process_accepted_transaction( const chain::transacti
using bsoncxx::builder::basic::make_array;
namespace bbb = bsoncxx::builder::basic;
const auto& trx = t->trx;
const signed_transaction& trx = t->packed_trx->get_signed_transaction();
if( !filter_include( trx ) ) return;
......@@ -1095,11 +1095,8 @@ void mongo_db_plugin_impl::_process_irreversible_block(const chain::block_state_
string trx_id_str;
if( receipt.trx.contains<packed_transaction>() ) {
const auto& pt = receipt.trx.get<packed_transaction>();
// get id via get_raw_transaction() as packed_transaction.id() mutates internal transaction state
const auto& raw = pt.get_raw_transaction();
const auto& trx = fc::raw::unpack<transaction>( raw );
if( !filter_include( trx ) ) continue;
const auto& id = trx.id();
if( !filter_include( pt.get_signed_transaction() ) ) continue;
const auto& id = pt.id();
trx_id_str = id.str();
} else {
const auto& id = receipt.trx.get<transaction_id_type>();
......
......@@ -58,13 +58,14 @@ std::pair<signed_block_ptr, signed_block_ptr> corrupt_trx_in_block(validating_te
// Make a copy of the valid block and corrupt the transaction
auto copy_b = std::make_shared<signed_block>(b->clone());
auto signed_tx = copy_b->transactions.back().trx.get<packed_transaction>().get_signed_transaction();
const auto& packed_trx = copy_b->transactions.back().trx.get<packed_transaction>();
auto signed_tx = packed_trx.get_signed_transaction();
// Corrupt one signature
signed_tx.signatures.clear();
signed_tx.sign(main.get_private_key(act_name, "active"), main.control->get_chain_id());
// Replace the valid transaction with the invalid transaction
auto invalid_packed_tx = packed_transaction(signed_tx);
auto invalid_packed_tx = packed_transaction(signed_tx, packed_trx.get_compression());
copy_b->transactions.back().trx = invalid_packed_tx;
// Re-calculate the transaction merkle
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册