Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

CFD: Initial support for pruned_block #8853

Merged
merged 11 commits into from
Mar 24, 2020
41 changes: 40 additions & 1 deletion libraries/chain/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ namespace eosio { namespace chain {
}
}

static fc::static_variant<transaction_id_type, pruned_transaction> translate_transaction_receipt(const transaction_id_type& tid) {
return tid;
}
static fc::static_variant<transaction_id_type, pruned_transaction> translate_transaction_receipt(const packed_transaction& ptrx) {
return pruned_transaction(ptrx);
}

pruned_transaction_receipt::pruned_transaction_receipt(const transaction_receipt& other)
: transaction_receipt_header(static_cast<const transaction_receipt_header&>(other)),
trx(other.trx.visit([&](const auto& obj) { return translate_transaction_receipt(obj); }))
{}

flat_multimap<uint16_t, block_extension> signed_block::validate_and_extract_extensions()const {
using decompose_t = block_extension_types::decompose_t;

Expand Down Expand Up @@ -61,4 +73,31 @@ namespace eosio { namespace chain {

}

} } /// namespace eosio::chain
pruned_block::pruned_block( const signed_block& other )
: signed_block_header(static_cast<const signed_block_header&>(other)),
prune_state(prune_state_type::complete_legacy),
transactions(other.transactions.begin(), other.transactions.end()),
block_extensions(other.block_extensions)
{}

static std::size_t pruned_trx_receipt_packed_size(const pruned_transaction& obj, pruned_transaction::compression_type segment_compression) {
return obj.maximum_pruned_pack_size(segment_compression);
}
static std::size_t pruned_trx_receipt_packed_size(const transaction_id_type& obj, pruned_transaction::compression_type) {
return fc::raw::pack_size(obj);
}

std::size_t pruned_transaction_receipt::maximum_pruned_pack_size( pruned_transaction::compression_type segment_compression ) const {
return fc::raw::pack_size(*static_cast<const transaction_receipt_header*>(this)) + 1 +
trx.visit([&](const auto& obj){ return pruned_trx_receipt_packed_size(obj, segment_compression); });
}

std::size_t pruned_block::maximum_pruned_pack_size( pruned_transaction::compression_type segment_compression ) const {
std::size_t result = fc::raw::pack_size(fc::unsigned_int(transactions.size()));
for(const pruned_transaction_receipt& r: transactions) {
result += r.maximum_pruned_pack_size( segment_compression );
}
return fc::raw::pack_size(*static_cast<const signed_block_header*>(this)) + fc::raw::pack_size(prune_state) + result + fc::raw::pack_size(block_extensions);
}

} } /// namespace eosio::chain
76 changes: 76 additions & 0 deletions libraries/chain/include/eosio/chain/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,79 @@ namespace eosio { namespace chain {
};
using signed_block_ptr = std::shared_ptr<signed_block>;

struct pruned_transaction_receipt : public transaction_receipt_header {

pruned_transaction_receipt():transaction_receipt_header(){}
pruned_transaction_receipt(const transaction_receipt&);
swatanabe-b1 marked this conversation as resolved.
Show resolved Hide resolved
explicit pruned_transaction_receipt( const transaction_id_type& tid ):transaction_receipt_header(executed),trx(tid){}
explicit pruned_transaction_receipt( const pruned_transaction& ptrx ):transaction_receipt_header(executed),trx(ptrx){}

fc::static_variant<transaction_id_type, pruned_transaction> trx;

std::size_t maximum_pruned_pack_size( pruned_transaction::compression_type segment_compression ) const;

digest_type digest()const {
digest_type::encoder enc;
fc::raw::pack( enc, status );
fc::raw::pack( enc, cpu_usage_us );
fc::raw::pack( enc, net_usage_words );
if( trx.contains<transaction_id_type>() )
fc::raw::pack( enc, trx.get<transaction_id_type>() );
else
fc::raw::pack( enc, trx.get<pruned_transaction>().packed_digest() );
return enc.result();
}
};

struct pruned_block : public signed_block_header{
private:
pruned_block( const pruned_block& ) = default;
public:
enum class prune_state_type : uint8_t { incomplete, complete, complete_legacy };

pruned_block() = default;
explicit pruned_block( const signed_block_header& h ):signed_block_header(h){}
pruned_block( const signed_block& );
swatanabe-b1 marked this conversation as resolved.
Show resolved Hide resolved
pruned_block( pruned_block&& ) = default;
pruned_block& operator=(const pruned_block&) = delete;
pruned_block clone() const { return *this; }

fc::enum_type<uint8_t,prune_state_type> prune_state{prune_state_type::complete_legacy};
deque<pruned_transaction_receipt> transactions; /// new or generated transactions
extensions_type block_extensions;

std::size_t maximum_pruned_pack_size( pruned_transaction::compression_type segment_compression ) const;

template<typename Stream>
void pack_with_padding(Stream& stream, pruned_transaction::compression_type segment_compression) {
std::size_t padded_size = maximum_pruned_pack_size( segment_compression );
pack_with_padding(stream, segment_compression, padded_size);
}
template<typename Stream>
void pack_with_padding(Stream& stream, pruned_transaction::compression_type segment_compression, std::size_t padded_size) {
fc::raw::pack(stream, fc::unsigned_int(padded_size));
arhag marked this conversation as resolved.
Show resolved Hide resolved
std::size_t pos = stream.tellp();
fc::raw::pack(stream, *this);
std::size_t actual_size = stream.tellp() - pos;
for(std::size_t i = 0; i < padded_size - actual_size; ++i) {
arhag marked this conversation as resolved.
Show resolved Hide resolved
stream.put('\0');
}
}
template<typename Stream>
std::size_t unpack_with_padding(Stream& stream, pruned_transaction::compression_type segment_compression) {
fc::unsigned_int padded_size;
fc::raw::unpack(stream, padded_size);
std::size_t pos = stream.tellp();
fc::raw::unpack(stream, *this);
std::size_t actual_size = stream.tellp() - pos;
stream.skip( padded_size - actual_size );
return padded_size;
}

flat_multimap<uint16_t, block_extension> validate_and_extract_extensions()const;
arhag marked this conversation as resolved.
Show resolved Hide resolved
};
using pruned_block_ptr = std::shared_ptr<pruned_block>;

struct producer_confirmation {
block_id_type block_id;
digest_type block_digest;
Expand All @@ -119,3 +192,6 @@ FC_REFLECT(eosio::chain::transaction_receipt_header, (status)(cpu_usage_us)(net_
FC_REFLECT_DERIVED(eosio::chain::transaction_receipt, (eosio::chain::transaction_receipt_header), (trx) )
FC_REFLECT(eosio::chain::additional_block_signatures_extension, (signatures));
FC_REFLECT_DERIVED(eosio::chain::signed_block, (eosio::chain::signed_block_header), (transactions)(block_extensions) )

FC_REFLECT_DERIVED(eosio::chain::pruned_transaction_receipt, (eosio::chain::transaction_receipt_header), (trx) )
FC_REFLECT_DERIVED(eosio::chain::pruned_block, (eosio::chain::signed_block_header), (prune_state)(transactions)(block_extensions) )
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ namespace eosio { namespace chain {
3040017, "Transaction includes disallowed extensions (invalid block)" )
FC_DECLARE_DERIVED_EXCEPTION( tx_resource_exhaustion, transaction_exception,
3040018, "Transaction exceeded transient resource limit" )
FC_DECLARE_DERIVED_EXCEPTION( tx_prune_exception, transaction_exception,
3040019, "Prunable data not found" )


FC_DECLARE_DERIVED_EXCEPTION( action_validate_exception, chain_exception,
Expand Down
112 changes: 112 additions & 0 deletions libraries/chain/include/eosio/chain/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,111 @@ namespace eosio { namespace chain {
transaction_id_type trx_id;
};

struct prunable_transaction_data {
using compression_type = packed_transaction::compression_type;
arhag marked this conversation as resolved.
Show resolved Hide resolved

struct none {
digest_type prunable_digest;
};

struct signatures_only {
std::vector<signature_type> signatures;
digest_type context_free_mroot;
};

using segment_type = fc::static_variant<digest_type, std::vector<char>>;

struct partial {
std::vector<signature_type> signatures;
std::vector<segment_type> context_free_segments;
};

struct full {
std::vector<signature_type> signatures;
std::vector<std::vector<char>> context_free_segments;
};

struct full_legacy {
std::vector<signature_type> signatures;
std::vector<char> packed_context_free_data;
};

using prunable_data_type = fc::static_variant< full_legacy,
none,
signatures_only,
partial,
full >;

prunable_transaction_data prune_all() const;
digest_type digest() const;

// Returns the maximum pack size of any prunable_transaction_data that is reachable
// by pruning this object.
std::size_t maximum_pruned_pack_size( compression_type segment_compression ) const;

prunable_data_type prunable_data;
};

struct pruned_transaction : fc::reflect_init {
using compression_type = packed_transaction::compression_type;

pruned_transaction() = default;
pruned_transaction(pruned_transaction&&) = default;
explicit pruned_transaction(const pruned_transaction&) = default;
pruned_transaction& operator=(const pruned_transaction&) = delete;
pruned_transaction& operator=(pruned_transaction&&) = default;

pruned_transaction(const packed_transaction& other) : pruned_transaction(other.get_signed_transaction(), true, other.get_compression()) {}
swatanabe-b1 marked this conversation as resolved.
Show resolved Hide resolved
explicit pruned_transaction(const signed_transaction& t, bool legacy, compression_type _compression = compression_type::none);
explicit pruned_transaction(signed_transaction&& t, bool legacy, compression_type _compression = compression_type::none);

#if 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code need to be kept around?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'll be needed eventually.

// used by abi_serializer
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 );
#endif

uint32_t get_unprunable_size()const;
uint32_t get_prunable_size()const;

digest_type packed_digest()const;

const transaction_id_type& id()const { return trx_id; }

time_point_sec expiration()const { return unpacked_trx.expiration; }
const transaction& get_transaction()const { return unpacked_trx; }
const signed_transaction& get_signed_transaction()const { return unpacked_trx; }
// Returns nullptr if the signatures were pruned
const vector<signature_type>* get_signatures()const;
// Returns nullptr if any context_free_data segment was pruned
const vector<bytes>* get_context_free_data()const;
// Returns nullptr if the context_free_data segment was pruned segment_ordinal is out of range.
arhag marked this conversation as resolved.
Show resolved Hide resolved
const bytes* get_context_free_data(std::size_t segment_ordinal);
const fc::enum_type<uint8_t,compression_type>& get_compression()const { return compression; }
const bytes& get_packed_transaction()const { return packed_trx; }

void prune_all();

std::size_t maximum_pruned_pack_size( compression_type segment_compression ) const;

private:

friend struct fc::reflector<pruned_transaction>;
friend struct fc::reflector_init_visitor<pruned_transaction>;
friend struct fc::has_reflector_init<pruned_transaction>;
void reflector_init();
private:
fc::enum_type<uint8_t,compression_type> compression;
arhag marked this conversation as resolved.
Show resolved Hide resolved
prunable_transaction_data prunable_data;
bytes packed_trx;

private:
// cache unpacked trx, for thread safety do not modify after construction
signed_transaction unpacked_trx;
transaction_id_type trx_id;
};

using packed_transaction_ptr = std::shared_ptr<packed_transaction>;

uint128_t transaction_id_to_sender_id( const transaction_id_type& tid );
Expand All @@ -217,3 +322,10 @@ FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction
FC_REFLECT_ENUM( eosio::chain::packed_transaction::compression_type, (none)(zlib))
// @ignore unpacked_trx
FC_REFLECT( eosio::chain::packed_transaction, (signatures)(compression)(packed_context_free_data)(packed_trx) )
FC_REFLECT( eosio::chain::pruned_transaction, (compression)(prunable_data)(packed_trx) )
FC_REFLECT( eosio::chain::prunable_transaction_data, (prunable_data));
FC_REFLECT( eosio::chain::prunable_transaction_data::none, (prunable_digest))
FC_REFLECT( eosio::chain::prunable_transaction_data::signatures_only, (signatures)(context_free_mroot))
FC_REFLECT( eosio::chain::prunable_transaction_data::partial, (signatures)(context_free_segments))
FC_REFLECT( eosio::chain::prunable_transaction_data::full, (signatures)(context_free_segments))
FC_REFLECT( eosio::chain::prunable_transaction_data::full_legacy, (signatures)(packed_context_free_data))
Loading