5#include <boost/range/adaptor/transformed.hpp>
6#include <boost/iostreams/filtering_stream.hpp>
7#include <boost/iostreams/device/back_inserter.hpp>
8#include <boost/iostreams/filter/zlib.hpp>
14namespace sysio {
namespace chain {
18 "deferred_transaction_generation_context expects FC to support reflector_init" );
22 "Deferred transaction generation context extension must have a non-empty sender account",
38 "declared max_net_usage_words overflows when expanded to max net usage" );
61 flat_set<public_key_type>& recovered_pub_keys,
bool allow_duplicate_keys)
const
64 recovered_pub_keys.clear();
69 SYS_ASSERT( now < deadline, tx_cpu_usage_exceeded,
"transaction signature verification executed for too long ${time}us",
70 (
"time", now - start)(
"now", now)(
"deadline", deadline)(
"start", start) );
71 auto[ itr, successful_insertion ] = recovered_pub_keys.emplace( sig,
digest );
72 SYS_ASSERT( allow_duplicate_keys || successful_insertion, tx_duplicate_sig,
73 "transaction includes more than one signature signed using the same key associated with public key: ${key}",
83 flat_multimap<uint16_t, transaction_extension>
results;
91 SYS_ASSERT(
id >= id_type_lower_bound, invalid_transaction_extension,
92 "Transaction extensions are not in the correct order (ascending id types required)"
95 auto iter =
results.emplace(std::piecewise_construct,
96 std::forward_as_tuple(
id),
97 std::forward_as_tuple()
100 auto match = decompose_t::extract<transaction_extension>(
id, e.second, iter->second );
101 SYS_ASSERT( match, invalid_transaction_extension,
102 "Transaction extension with id type ${id} is not supported",
106 if( match->enforce_unique ) {
107 SYS_ASSERT( i == 0 ||
id > id_type_lower_bound, invalid_transaction_extension,
108 "Transaction extension with id type ${id} is not allowed to repeat",
113 id_type_lower_bound =
id;
121 return signatures.back();
130 flat_set<public_key_type>& recovered_pub_keys,
131 bool allow_duplicate_keys)
const
137 uint64_t size = config::fixed_net_overhead_of_packed_trx;
138 size += packed_trx.size();
139 SYS_ASSERT( size <= std::numeric_limits<uint32_t>::max(), tx_too_big,
"packed_transaction is too big" );
145 size += packed_context_free_data.size();
146 SYS_ASSERT( size <= std::numeric_limits<uint32_t>::max(), tx_too_big,
"packed_transaction is too big" );
153 return sizeof(*this) +
155 packed_context_free_data.size() * 2 +
156 packed_trx.size() * 2;
173namespace bio = boost::iostreams;
175template<
size_t Limit>
180 template<
typename Sink>
183 SYS_ASSERT(
_total +
count <= Limit, tx_decompression_error,
"Exceeded maximum decompressed transaction size");
185 return bio::write(sink,
s,
count);
192 if( data.size() == 0 )
202static bytes zlib_decompress(
const bytes& data) {
205 bio::filtering_ostream decomp;
206 decomp.push(bio::zlib_decompressor());
207 decomp.push(read_limiter<1*1024*1024>());
208 decomp.push(bio::back_inserter(out));
209 bio::write(decomp, data.data(), data.size());
220static vector<bytes> zlib_decompress_context_free_data(
const bytes& data) {
221 if( data.size() == 0 )
222 return vector<bytes>();
224 bytes out = zlib_decompress(data);
225 return unpack_context_free_data(out);
228static transaction zlib_decompress_transaction(
const bytes& data) {
229 bytes out = zlib_decompress(data);
230 return unpack_transaction(out);
233static bytes pack_transaction(
const transaction& t) {
237static bytes pack_context_free_data(
const vector<bytes>& cfd ) {
238 if( cfd.size() == 0 )
244static bytes zlib_compress_context_free_data(
const vector<bytes>& cfd ) {
245 if( cfd.size() == 0 )
248 bytes in = pack_context_free_data(cfd);
250 bio::filtering_ostream comp;
251 comp.push(bio::zlib_compressor(bio::zlib::best_compression));
252 comp.push(bio::back_inserter(out));
253 bio::write(comp, in.data(), in.size());
258static bytes zlib_compress_transaction(
const transaction& t) {
259 bytes in = pack_transaction(t);
261 bio::filtering_ostream comp;
262 comp.push(bio::zlib_compressor(bio::zlib::best_compression));
263 comp.push(bio::back_inserter(out));
264 bio::write(comp, in.data(), in.size());
272 switch(compression) {
276 return zlib_decompress(packed_trx);
278 SYS_THROW(unknown_transaction_compression,
"Unknown transaction compression algorithm");
284:signatures(
std::move(sigs))
285,compression(_compression)
286,packed_context_free_data(
std::move(packed_cfd))
287,packed_trx(
std::move(packed_txn))
289 local_unpack_transaction({});
290 if( !packed_context_free_data.empty() ) {
291 local_unpack_context_free_data();
296:signatures(
std::move(sigs))
297,compression(_compression)
298,packed_trx(
std::move(packed_txn))
300 local_unpack_transaction( std::move( cfd ) );
302 local_pack_context_free_data();
307:signatures(
std::move(sigs))
308,compression(_compression)
309,packed_context_free_data(
std::move(packed_cfd))
310,unpacked_trx(
std::move(t), signatures, {})
311,trx_id(unpacked_trx.id())
313 local_pack_transaction();
314 if( !packed_context_free_data.empty() ) {
315 local_unpack_context_free_data();
319void packed_transaction::reflector_init()
323 "FC unpack needs to call reflector_init otherwise unpacked_trx will not be initialized");
324 SYS_ASSERT( unpacked_trx.
expiration == time_point_sec(), tx_decompression_error,
"packed_transaction already unpacked" );
325 local_unpack_transaction({});
326 local_unpack_context_free_data();
329void packed_transaction::local_unpack_transaction(vector<bytes>&& context_free_data)
332 switch( compression ) {
334 unpacked_trx = signed_transaction( unpack_transaction( packed_trx ), signatures, std::move(context_free_data) );
337 unpacked_trx = signed_transaction( zlib_decompress_transaction( packed_trx ), signatures, std::move(context_free_data) );
340 SYS_THROW( unknown_transaction_compression,
"Unknown transaction compression algorithm" );
342 trx_id = unpacked_trx.
id();
346void packed_transaction::local_unpack_context_free_data()
350 switch( compression ) {
352 unpacked_trx.
context_free_data = unpack_context_free_data( packed_context_free_data );
355 unpacked_trx.
context_free_data = zlib_decompress_context_free_data( packed_context_free_data );
358 SYS_THROW( unknown_transaction_compression,
"Unknown transaction compression algorithm" );
363void packed_transaction::local_pack_transaction()
366 switch(compression) {
368 packed_trx = pack_transaction(unpacked_trx);
371 packed_trx = zlib_compress_transaction(unpacked_trx);
374 SYS_THROW(unknown_transaction_compression,
"Unknown transaction compression algorithm");
379void packed_transaction::local_pack_context_free_data()
382 switch(compression) {
384 packed_context_free_data = pack_context_free_data(unpacked_trx.
context_free_data);
387 packed_context_free_data = zlib_compress_context_free_data(unpacked_trx.
context_free_data);
390 SYS_THROW(unknown_transaction_compression,
"Unknown transaction compression algorithm");
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Used to generate a useful error report when an exception is thrown.
static sha256 hash(const char *d, uint32_t dlen)
re-thrown whenever an unhandled exception is caught.Any exceptions thrown by 3rd party libraries that...
#define FC_CAPTURE_AND_RETHROW(...)
#define FC_LOG_MESSAGE(LOG_LEVEL, FORMAT,...)
A helper method for generating log messages.
void unpack(Stream &s, std::deque< T > &value)
constexpr bool has_feature_reflector_init_on_unpacked_reflected_types
void pack(Stream &s, const std::deque< T > &value)
size_t pack_size(const T &v)
fc::sha256 digest(const T &value)
uint32_t endian_reverse_u32(uint32_t x)
checksum_type digest_type
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type Block can not be found Unlinkable block Block does not guarantee concurrent execution without conflicts Block exhausted allowed resources Block is from the future Block is not signed by expected producer Block includes an ill formed protocol feature activation extension Block includes an ill formed additional block signature extension transaction_exception
unsigned __int64 uint64_t
decompose< Ts... > decompose_t
bytes get_raw_transaction() const
packed_transaction()=default
digest_type packed_digest() const
uint32_t get_unprunable_size() const
uint32_t get_prunable_size() const
size_t get_estimated_size() const
size_t write(Sink &sink, const char *s, size_t count)
bio::multichar_output_filter_tag category
vector< bytes > context_free_data
for each context-free action, there is an entry here
fc::microseconds get_signature_keys(const chain_id_type &chain_id, fc::time_point deadline, flat_set< public_key_type > &recovered_pub_keys, bool allow_duplicate_keys=false) const
const signature_type & sign(const private_key_type &key, const chain_id_type &chain_id)
extensions_type transaction_extensions
fc::microseconds get_signature_keys(const vector< signature_type > &signatures, const chain_id_type &chain_id, fc::time_point deadline, const vector< bytes > &cfd, flat_set< public_key_type > &recovered_pub_keys, bool allow_duplicate_keys=false) const
digest_type sig_digest(const chain_id_type &chain_id, const vector< bytes > &cfd=vector< bytes >()) const
transaction_id_type id() const
flat_multimap< uint16_t, transaction_extension > validate_and_extract_extensions() const
account_query_db::get_accounts_by_authorizers_result results