tester.cpp 13.8 KB
Newer Older
1
#include <boost/test/unit_test.hpp>
2 3
#include <eosio/testing/tester.hpp>
#include <eosio/chain/asset.hpp>
4
#include <eosio/chain/wast_to_wasm.hpp>
5
#include <eosio/chain/contracts/types.hpp>
6
#include <eosio/chain/contracts/eos_contract.hpp>
7
#include <eosio/chain/contracts/contract_table_objects.hpp>
8

B
Bart Wyatt 已提交
9 10
#include <test.system/test.system.wast.hpp>
#include <test.system/test.system.abi.hpp>
11

12
#include <fc/utility.hpp>
13
#include <fc/io/json.hpp>
14 15 16 17 18

#include "WAST/WAST.h"
#include "WASM/WASM.h"
#include "IR/Module.h"
#include "IR/Validate.h"
19

20
namespace eosio { namespace testing {
21

22
   base_tester::base_tester(chain_controller::runtime_limits limits) {
23 24 25 26 27
      cfg.block_log_dir      = tempdir.path() / "blocklog";
      cfg.shared_memory_dir  = tempdir.path() / "shared";
      cfg.shared_memory_size = 1024*1024*8;

      cfg.genesis.initial_timestamp = fc::time_point::from_iso_string("2020-01-01T00:00:00.000");
D
Daniel Larimer 已提交
28
      cfg.genesis.initial_key = get_public_key( config::system_account_name, "active" );
29
      cfg.limits = limits;
30 31 32
      open();
   }

33
   public_key_type  base_tester::get_public_key( name keyname, string role ) const {
34
      return get_private_key( keyname, role ).get_public_key();
35 36
   }

37
   private_key_type base_tester::get_private_key( name keyname, string role ) const {
38 39 40
      return private_key_type::regenerate<fc::ecc::private_key_shim>(fc::sha256::hash(string(keyname)+role));
   }

41
   void base_tester::close() {
42
      control.reset();
43
      chain_transactions.clear();
44
   }
45 46

   void base_tester::open() {
47
      control.reset( new chain_controller(cfg) );
48
      chain_transactions.clear();
49
      control->applied_block.connect([this]( const block_trace& trace ){
50
         for( const auto& region : trace.block.regions) {
51 52
            for( const auto& cycle : region.cycles_summary ) {
               for ( const auto& shard : cycle ) {
B
Bart Wyatt 已提交
53
                  for( const auto& receipt: shard.transactions ) {
54 55
                     chain_transactions.emplace(receipt.id, receipt);
                  }
56 57 58 59
               }
            }
         }
      });
60 61
   }

62
   signed_block base_tester::produce_block( fc::microseconds skip_time ) {
63 64 65 66
      auto head_time = control->head_block_time();
      auto next_time = head_time + skip_time;
      uint32_t slot  = control->get_slot_at_time( next_time );
      auto sch_pro   = control->get_scheduled_producer(slot);
K
Kevin Heifner 已提交
67
      auto priv_key  = get_private_key( sch_pro, "active" );
68

69
      return control->generate_block( next_time, sch_pro, priv_key, skip_missed_block_penalty );
70 71
   }

72
   void base_tester::produce_blocks( uint32_t n ) {
73 74 75 76
      for( uint32_t i = 0; i < n; ++i )
         produce_block();
   }

77
  void base_tester::set_tapos( signed_transaction& trx ) const {
78 79 80
     trx.set_reference_block( control->head_block_id() );
  }

81
   void base_tester::create_account( account_name a, account_name creator, bool multisig ) {
82 83 84
      signed_transaction trx;
      set_tapos( trx );

85 86 87 88 89 90 91 92
      authority owner_auth;
      if (multisig) {
         // multisig between account's owner key and creators active permission
         owner_auth = authority(2, {key_weight{get_public_key( a, "owner" ), 1}}, {permission_level_weight{{creator, config::active_name}, 1}});
      } else {
         owner_auth =  authority( get_public_key( a, "owner" ) );
      }

93
      trx.actions.emplace_back( vector<permission_level>{{creator,config::active_name}},
94
                                contracts::newaccount{
95 96
                                   .creator  = creator,
                                   .name     = a,
97
                                   .owner    = owner_auth,
98 99 100
                                   .active   = authority( get_public_key( a, "active" ) ),
                                   .recovery = authority( get_public_key( a, "recovery" ) ),
                                });
101

102 103 104 105
      set_tapos(trx);
      trx.sign( get_private_key( creator, "active" ), chain_id_type()  );
      push_transaction( trx );
   }
106

107
   transaction_trace base_tester::push_transaction( packed_transaction& trx ) {
108
      return control->push_transaction( trx );
109 110
   }

111
   transaction_trace base_tester::push_transaction( signed_transaction& trx ) {
112 113
      auto ptrx = packed_transaction(trx);
      return push_transaction( ptrx );
114 115
   }

116
   base_tester::action_result base_tester::push_action(action&& cert_act, uint64_t authorizer) {
117 118 119 120 121 122 123 124 125 126
      signed_transaction trx;
      if (authorizer) {
         cert_act.authorization = vector<permission_level>{{authorizer, config::active_name}};
      }
      trx.actions.emplace_back(std::move(cert_act));
      set_tapos(trx);
      if (authorizer) {
         trx.sign(get_private_key(authorizer, "active"), chain_id_type());
      }
      try {
A
Anton Perkov 已提交
127
         push_transaction(trx);
128 129 130 131 132 133 134 135
      } catch (const fc::exception& ex) {
         return error(ex.top_message());
      }
      produce_block();
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      return success();
   }

136 137 138
   transaction_trace base_tester::push_action( const account_name& code,
                             const action_name& acttype,
                             const account_name& actor,
139
                             const variant_object& data
140
                             )
141
   { try {
142
      chain::contracts::abi_serializer abis( control->get_database().get<account_object,by_name>(code).get_abi() );
143 144

      string action_type_name = abis.get_action_type(acttype);
145

146 147 148 149 150 151
      action act;
      act.account = code;
      act.name = acttype;
      act.authorization = vector<permission_level>{{actor, config::active_name}};
      act.data = abis.variant_to_binary(action_type_name, data);
      wdump((act));
152

153 154 155 156 157 158 159 160 161
      signed_transaction trx;
      trx.actions.emplace_back(std::move(act));
      set_tapos(trx);
      trx.sign(get_private_key(actor, "active"), chain_id_type());
      wdump((get_public_key( actor, "active" )));;

      return push_transaction(trx);
   } FC_CAPTURE_AND_RETHROW( (code)(acttype)(actor) ) }

162
   transaction_trace base_tester::push_reqauth( account_name from, const vector<permission_level>& auths, const vector<private_key_type>& keys ) {
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
      variant pretty_trx = fc::mutable_variant_object()
         ("actions", fc::variants({
            fc::mutable_variant_object()
               ("account", name(config::system_account_name))
               ("name", "reqauth")
               ("authorization", auths)
               ("data", fc::mutable_variant_object()
                  ("from", from)
               )
            })
        );

      signed_transaction trx;
      contracts::abi_serializer::from_variant(pretty_trx, trx, get_resolver());
      set_tapos( trx );
      for(auto iter = keys.begin(); iter != keys.end(); iter++)
         trx.sign( *iter, chain_id_type() );
      return push_transaction( trx );
   }

183 184 185 186 187 188 189 190 191 192
    transaction_trace base_tester::push_reqauth(account_name from, string role, bool multi_sig) {
        if (!multi_sig) {
            return push_reqauth(from, vector<permission_level>{{from, config::owner_name}},
                                        {get_private_key(from, role)});
        } else {
            return push_reqauth(from, vector<permission_level>{{from, config::owner_name}},
                                        {get_private_key(from, role), get_private_key( config::system_account_name, "active" )} );
        }
    }

193
   transaction_trace base_tester::push_nonce(account_name from, const string& v) {
194 195 196
      variant pretty_trx = fc::mutable_variant_object()
         ("actions", fc::variants({
            fc::mutable_variant_object()
197
               ("account", name(config::system_account_name))
198 199 200 201
               ("name", "nonce")
               ("authorization", fc::variants({
                  fc::mutable_variant_object()
                     ("actor", from)
202
                     ("permission", name(config::active_name))
203 204 205 206 207 208 209 210
               }))
               ("data", fc::mutable_variant_object()
                  ("value", v)
               )
            })
         );

      signed_transaction trx;
211
      contracts::abi_serializer::from_variant(pretty_trx, trx, get_resolver());
212 213
      set_tapos( trx );

214
      trx.sign( get_private_key( from, "active" ), chain_id_type() );
215 216
      return push_transaction( trx );
   }
217

218
   transaction_trace base_tester::transfer( account_name from, account_name to, string amount, string memo, account_name currency ) {
219
      return transfer( from, to, asset::from_string(amount), memo, currency );
220
   }
221

222
   transaction_trace base_tester::transfer( account_name from, account_name to, asset amount, string memo, account_name currency ) {
223 224 225 226 227 228 229 230 231 232 233 234 235
      variant pretty_trx = fc::mutable_variant_object()
         ("actions", fc::variants({
            fc::mutable_variant_object()
               ("account", currency)
               ("name", "transfer")
               ("authorization", fc::variants({
                  fc::mutable_variant_object()
                     ("actor", from)
                     ("permission", name(config::active_name))
               }))
               ("data", fc::mutable_variant_object()
                  ("from", from)
                  ("to", to)
K
Kevin Heifner 已提交
236
                  ("quantity", amount)
237 238 239 240 241
                  ("memo", memo)
               )
            })
         );

242
      signed_transaction trx;
243
      contracts::abi_serializer::from_variant(pretty_trx, trx, get_resolver());
244
      set_tapos( trx );
245

246
      trx.sign( get_private_key( from, name(config::active_name).to_string() ), chain_id_type()  );
247
      return push_transaction( trx );
248 249
   }

250
   void base_tester::set_authority( account_name account,
251 252 253 254 255 256 257 258
                               permission_name perm,
                               authority auth,
                               permission_name parent ) { try {
      signed_transaction trx;
      trx.actions.emplace_back( vector<permission_level>{{account,perm}},
                                contracts::updateauth{
                                   .account    = account,
                                   .permission = perm,
259 260
                                   .parent     = parent,
                                   .data       = move(auth),
261 262 263
                                });

      set_tapos( trx );
264
      trx.sign( get_private_key( account, "active" ), chain_id_type()  );
265
      push_transaction( trx );
266 267
   } FC_CAPTURE_AND_RETHROW( (account)(perm)(auth)(parent) ) }

268
   void base_tester::set_code( account_name account, const char* wast ) try {
269
      auto wasm = wast_to_wasm(wast);
270 271 272 273 274 275 276 277 278 279 280 281

      signed_transaction trx;
      trx.actions.emplace_back( vector<permission_level>{{account,config::active_name}},
                                contracts::setcode{
                                   .account    = account,
                                   .vmtype     = 0,
                                   .vmversion  = 0,
                                   .code       = bytes(wasm.begin(), wasm.end())
                                });

      set_tapos( trx );
      trx.sign( get_private_key( account, "active" ), chain_id_type()  );
282
      push_transaction( trx );
283 284
   } FC_CAPTURE_AND_RETHROW( (account)(wast) )

285
   void base_tester::set_abi( account_name account, const char* abi_json) {
286 287 288 289 290 291 292 293 294 295
      auto abi = fc::json::from_string(abi_json).template as<contracts::abi_def>();
      signed_transaction trx;
      trx.actions.emplace_back( vector<permission_level>{{account,config::active_name}},
                                contracts::setabi{
                                   .account    = account,
                                   .abi        = abi
                                });

      set_tapos( trx );
      trx.sign( get_private_key( account, "active" ), chain_id_type()  );
296
      push_transaction( trx );
297 298
   }

299
   bool base_tester::chain_has_transaction( const transaction_id_type& txid ) const {
300 301 302
      return chain_transactions.count(txid) != 0;
   }

303
   const transaction_receipt& base_tester::get_transaction_receipt( const transaction_id_type& txid ) const {
304 305 306
      return chain_transactions.at(txid);
   }

D
Daniel Larimer 已提交
307 308 309
   /**
    *  Reads balance as stored by generic_currency contract
    */
310
   asset base_tester::get_currency_balance( const account_name& code,
K
Khaled Al-Hassanieh 已提交
311 312
                                       const symbol&       asset_symbol,
                                       const account_name& account ) const {
D
Daniel Larimer 已提交
313
      const auto& db  = control->get_database();
314
      const auto* tbl = db.find<contracts::table_id_object, contracts::by_code_scope_table>(boost::make_tuple(code, account, N(account)));
315 316 317 318
      share_type result = 0;

      // the balance is implied to be 0 if either the table or row does not exist
      if (tbl) {
319
         const auto *obj = db.find<contracts::key_value_object, contracts::by_scope_primary>(boost::make_tuple(tbl->id, asset_symbol.value()));
320
         if (obj) {
321
            //balance is the second field after symbol, so skip the symbol
322
            fc::datastream<const char *> ds(obj->value.data(), obj->value.size());
323 324 325
            fc::raw::unpack(ds, result);
         }
      }
K
Khaled Al-Hassanieh 已提交
326
      return asset(result, asset_symbol);
D
Daniel Larimer 已提交
327 328
   }

329
   vector<uint8_t> base_tester::to_uint8_vector(const string& s) {
330 331 332 333 334
      vector<uint8_t> v(s.size());
      copy(s.begin(), s.end(), v.begin());
      return v;
   };

335
   vector<uint8_t> base_tester::to_uint8_vector(uint64_t x) {
336 337 338 339 340
      vector<uint8_t> v(sizeof(x));
      *reinterpret_cast<uint64_t*>(v.data()) = x;
      return v;
   };

341
   uint64_t base_tester::to_uint64(fc::variant x) {
342 343 344 345 346 347
      vector<uint8_t> blob;
      fc::from_variant<uint8_t>(x, blob);
      FC_ASSERT(8 == blob.size());
      return *reinterpret_cast<uint64_t*>(blob.data());
   }

348
   string base_tester::to_string(fc::variant x) {
349 350 351 352 353 354
      vector<uint8_t> v;
      fc::from_variant<uint8_t>(x, v);
      string s(v.size(), 0);
      copy(v.begin(), v.end(), s.begin());
      return s;
   }
355

356 357 358 359
   tester::tester(chain_controller::runtime_limits limits)
      : base_tester(limits) {
      push_genesis_block();
   }
D
Daniel Larimer 已提交
360

361 362 363 364
   void tester::push_genesis_block() {
      set_code(config::system_account_name, test_system_wast);
      set_abi(config::system_account_name, test_system_abi);
   }
D
Daniel Larimer 已提交
365

366
} }  /// eosio::test