transaction.cpp 6.8 KB
Newer Older
A
Andrianto Lie 已提交
1 2 3
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
N
Nathan Hourt 已提交
4
 */
B
Bart Wyatt 已提交
5
#include <eosio/chain/exceptions.hpp>
N
Nathan Hourt 已提交
6 7 8 9 10
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
#include <fc/smart_ref_impl.hpp>
#include <algorithm>

11
#include <boost/range/adaptor/transformed.hpp>
M
Matt Witherspoon 已提交
12 13 14 15
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
16 17 18 19
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/filter/zlib.hpp>

20

P
Pravin 已提交
21
namespace eosio { namespace chain {
N
Nathan Hourt 已提交
22

M
Matt Witherspoon 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
using namespace boost::multi_index;

struct cached_pub_key {
   transaction_id_type trx_id;
   public_key_type pub_key;
   signature_type sig;
   cached_pub_key(const cached_pub_key&) = delete;
   cached_pub_key() = delete;
   cached_pub_key& operator=(const cached_pub_key&) = delete;
   cached_pub_key(cached_pub_key&&) = default;
};
struct by_sig{};

typedef multi_index_container<
   cached_pub_key,
   indexed_by<
      sequenced<>,
      hashed_unique<
         tag<by_sig>,
         member<cached_pub_key,
                signature_type,
                &cached_pub_key::sig>
      >
   >
> recovery_cache_type;

D
Daniel Larimer 已提交
49 50 51
void transaction_header::set_reference_block( const block_id_type& reference_block ) {
   ref_block_num    = fc::endian_reverse_u32(reference_block._hash[0]);
   ref_block_prefix = reference_block._hash[1];
N
Nathan Hourt 已提交
52 53
}

D
Daniel Larimer 已提交
54
bool transaction_header::verify_reference_block( const block_id_type& reference_block )const {
D
Daniel Larimer 已提交
55 56
   return ref_block_num    == (decltype(ref_block_num))fc::endian_reverse_u32(reference_block._hash[0]) &&
          ref_block_prefix == (decltype(ref_block_prefix))reference_block._hash[1];
57 58 59
}


D
Daniel Larimer 已提交
60
transaction_id_type transaction::id() const { 
N
Nathan Hourt 已提交
61
   digest_type::encoder enc;
D
Daniel Larimer 已提交
62
   fc::raw::pack( enc, *this );
N
Nathan Hourt 已提交
63 64 65
   return enc.result();
}

D
Daniel Larimer 已提交
66

67
digest_type transaction::sig_digest( const chain_id_type& chain_id, const vector<bytes>& cfd )const {
D
Daniel Larimer 已提交
68 69
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
D
Daniel Larimer 已提交
70
   fc::raw::pack( enc, *this );
71 72
   if( cfd.size() )
      fc::raw::pack( enc, cfd );
D
Daniel Larimer 已提交
73
   return enc.result();
N
Nathan Hourt 已提交
74 75
}

76
flat_set<public_key_type> transaction::get_signature_keys( const vector<signature_type>& signatures, const chain_id_type& chain_id, const vector<bytes>& cfd  )const
N
Nathan Hourt 已提交
77
{ try {
78
   using boost::adaptors::transformed;
M
Matt Witherspoon 已提交
79 80 81

   constexpr size_t recovery_cache_size = 100000;
   static recovery_cache_type recovery_cache;
82
   const digest_type digest = sig_digest(chain_id, cfd);
M
Matt Witherspoon 已提交
83 84 85 86 87

   flat_set<public_key_type> recovered_pub_keys;
   for(const signature_type& sig : signatures) {
      recovery_cache_type::index<by_sig>::type::iterator it = recovery_cache.get<by_sig>().find(sig);

88
      if(it == recovery_cache.get<by_sig>().end() || it->trx_id != id()) {
M
Matt Witherspoon 已提交
89
         public_key_type recov = public_key_type(sig, digest);
90
         recovery_cache.emplace_back( cached_pub_key{id(), recov, sig} ); //could fail on dup signatures; not a problem
M
Matt Witherspoon 已提交
91 92 93 94 95 96 97 98 99 100
         recovered_pub_keys.insert(recov);
         continue;
      }
      recovered_pub_keys.insert(it->pub_key);
   }

   while(recovery_cache.size() > recovery_cache_size)
      recovery_cache.erase(recovery_cache.begin());

   return recovered_pub_keys;
D
Daniel Larimer 已提交
101
} FC_CAPTURE_AND_RETHROW() }
N
Nathan Hourt 已提交
102

103 104

const signature_type& signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id) {
105
   signatures.push_back(key.sign(sig_digest(chain_id, context_free_data)));
106 107 108 109
   return signatures.back();
}

signature_type signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)const {
110
   return key.sign(sig_digest(chain_id, context_free_data));
111 112 113 114
}

flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const
{
115
   return transaction::get_signature_keys(signatures, chain_id, context_free_data);
116 117
}

118 119 120 121 122 123 124 125 126 127
namespace bio = boost::iostreams;

template<size_t Limit>
struct read_limiter {
   using char_type = char;
   using category = bio::multichar_output_filter_tag;

   template<typename Sink>
   size_t write(Sink &sink, const char* s, size_t count)
   {
B
Bart Wyatt 已提交
128
      EOS_ASSERT(_total + count <= Limit, tx_decompression_error, "Exceeded maximum decompressed transaction size");
129 130 131 132 133 134 135 136 137 138 139 140
      _total += count;
      return bio::write(sink, s, count);
   }

   size_t _total = 0;
};

static transaction unpack_transaction(const bytes& data) {
   return fc::raw::unpack<transaction>(data);
}


141 142 143 144 145
static bytes zlib_decompress(const bytes& data) {
   try {
      bytes out;
      bio::filtering_ostream decomp;
      decomp.push(bio::zlib_decompressor());
B
Bart Wyatt 已提交
146
      decomp.push(read_limiter<1*1024*1024>()); // limit to 10 megs decompressed for zip bomb protections
147 148 149 150 151 152 153 154 155 156 157 158
      decomp.push(bio::back_inserter(out));
      bio::write(decomp, data.data(), data.size());
      bio::close(decomp);
      return out;
   } catch( fc::exception& er ) {
      throw;
   } catch( ... ) {
      fc::unhandled_exception er( FC_LOG_MESSAGE( warn, "internal decompression error"), std::current_exception() );
      throw er;
   }
}

B
Bart Wyatt 已提交
159 160 161 162 163
static transaction zlib_decompress_transaction(const bytes& data) {
   bytes out = zlib_decompress(data);
   return unpack_transaction(out);
}

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
static bytes pack_transaction(const transaction& t) {
   return fc::raw::pack(t);
}

static bytes zlib_compress_transaction(const transaction& t) {
   bytes in = pack_transaction(t);
   bytes out;
   bio::filtering_ostream comp;
   comp.push(bio::zlib_compressor(bio::zlib::best_compression));
   comp.push(bio::back_inserter(out));
   bio::write(comp, in.data(), in.size());
   bio::close(comp);
   return out;
}

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
bytes packed_transaction::get_raw_transaction() const
{
   try {
      switch(compression) {
         case none:
            return data;
         case zlib:
            return zlib_decompress(data);
         default:
            FC_THROW("Unknown transaction compression algorithm");
      }
   } FC_CAPTURE_AND_RETHROW((compression)(data))
}

transaction packed_transaction::get_transaction()const
194 195 196 197 198 199 200 201 202 203 204 205 206
{
   try {
      switch(compression) {
         case none:
            return unpack_transaction(data);
         case zlib:
            return zlib_decompress_transaction(data);
         default:
            FC_THROW("Unknown transaction compression algorithm");
      }
   } FC_CAPTURE_AND_RETHROW((compression)(data))
}

207 208
signed_transaction packed_transaction::get_signed_transaction() const
{
209
   return signed_transaction(get_transaction(), signatures, context_free_data);
210 211 212
}

void packed_transaction::set_transaction(const transaction& t, packed_transaction::compression_type _compression)
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
{
   try {
      switch(_compression) {
         case none:
            data = pack_transaction(t);
            break;
         case zlib:
            data = zlib_compress_transaction(t);
            break;
         default:
            FC_THROW("Unknown transaction compression algorithm");
      }
   } FC_CAPTURE_AND_RETHROW((_compression)(t))
   compression = _compression;
}

N
Nathan Hourt 已提交
229

P
Pravin 已提交
230
} } // eosio::chain