wasm_tests.cpp 35.2 KB
Newer Older
1 2
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
3
#include <eosio/chain/contracts/abi_serializer.hpp>
M
Matt Witherspoon 已提交
4
#include <eosio/chain/wasm_eosio_constraints.hpp>
5
#include <eosio/chain/exceptions.hpp>
6
#include <asserter/asserter.wast.hpp>
7
#include <asserter/asserter.abi.hpp>
8

9 10
#include <stltest/stltest.wast.hpp>
#include <stltest/stltest.abi.hpp>
11

K
Khaled Al-Hassanieh 已提交
12 13
#include <noop/noop.wast.hpp>
#include <noop/noop.abi.hpp>
14

15 16
#include <eosio.system/eosio.system.wast.hpp>
#include <eosio.system/eosio.system.abi.hpp>
K
Khaled Al-Hassanieh 已提交
17

18
#include <Runtime/Runtime.h>
19

20
#include <fc/variant_object.hpp>
21
#include <fc/io/json.hpp>
22

23
#include "test_wasts.hpp"
24
#include "test_softfloat_wasts.hpp"
25

A
arhag 已提交
26 27 28
#include <array>
#include <utility>

29 30 31 32
using namespace eosio;
using namespace eosio::chain;
using namespace eosio::chain::contracts;
using namespace eosio::testing;
33
using namespace fc;
34

35

36 37 38 39
struct assertdef {
   int8_t      condition;
   string      message;

B
Bart Wyatt 已提交
40
   static account_name get_account() {
41 42 43 44 45 46 47 48 49 50 51
      return N(asserter);
   }

   static action_name get_name() {
      return N(procassert);
   }
};

FC_REFLECT(assertdef, (condition)(message));

struct provereset {
B
Bart Wyatt 已提交
52
   static account_name get_account() {
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
      return N(asserter);
   }

   static action_name get_name() {
      return N(provereset);
   }
};

FC_REFLECT_EMPTY(provereset);

BOOST_AUTO_TEST_SUITE(wasm_tests)

/**
 * Prove that action reading and assertions are working
 */
BOOST_FIXTURE_TEST_CASE( basic_test, tester ) try {
   produce_blocks(2);

71
   create_accounts( {N(asserter)} );
72 73 74 75 76 77 78 79 80 81 82 83 84
   produce_block();

   set_code(N(asserter), asserter_wast);
   produce_blocks(1);

   transaction_id_type no_assert_id;
   {
      signed_transaction trx;
      trx.actions.emplace_back( vector<permission_level>{{N(asserter),config::active_name}},
                                assertdef {1, "Should Not Assert!"} );

      set_tapos( trx );
      trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() );
85
      auto result = push_transaction( trx );
B
Bart Wyatt 已提交
86
      BOOST_CHECK_EQUAL(result.status, transaction_receipt::executed);
87 88
      BOOST_CHECK_EQUAL(result.action_traces.size(), 1);
      BOOST_CHECK_EQUAL(result.action_traces.at(0).receiver.to_string(),  name(N(asserter)).to_string() );
B
Bart Wyatt 已提交
89
      BOOST_CHECK_EQUAL(result.action_traces.at(0).act.account.to_string(), name(N(asserter)).to_string() );
90 91 92 93
      BOOST_CHECK_EQUAL(result.action_traces.at(0).act.name.to_string(),  name(N(procassert)).to_string() );
      BOOST_CHECK_EQUAL(result.action_traces.at(0).act.authorization.size(),  1 );
      BOOST_CHECK_EQUAL(result.action_traces.at(0).act.authorization.at(0).actor.to_string(),  name(N(asserter)).to_string() );
      BOOST_CHECK_EQUAL(result.action_traces.at(0).act.authorization.at(0).permission.to_string(),  name(config::active_name).to_string() );
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
      no_assert_id = trx.id();
   }

   produce_blocks(1);

   BOOST_REQUIRE_EQUAL(true, chain_has_transaction(no_assert_id));
   const auto& receipt = get_transaction_receipt(no_assert_id);
   BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status);

   transaction_id_type yes_assert_id;
   {
      signed_transaction trx;
      trx.actions.emplace_back( vector<permission_level>{{N(asserter),config::active_name}},
                                assertdef {0, "Should Assert!"} );

      set_tapos( trx );
      trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() );
      yes_assert_id = trx.id();
B
Bart Wyatt 已提交
112

113
      BOOST_CHECK_THROW(push_transaction( trx ), fc::assert_exception);
114 115 116 117
   }

   produce_blocks(1);

B
Bart Wyatt 已提交
118 119
   auto has_tx = chain_has_transaction(yes_assert_id);
   BOOST_REQUIRE_EQUAL(false, has_tx);
120 121 122 123 124 125 126 127 128

} FC_LOG_AND_RETHROW() /// basic_test

/**
 * Prove the modifications to global variables are wiped between runs
 */
BOOST_FIXTURE_TEST_CASE( prove_mem_reset, tester ) try {
   produce_blocks(2);

129
   create_accounts( {N(asserter)} );
130 131 132 133 134 135 136 137 138 139 140 141 142 143
   produce_block();

   set_code(N(asserter), asserter_wast);
   produce_blocks(1);

   // repeat the action multiple times, each time the action handler checks for the expected
   // default value then modifies the value which should not survive until the next invoction
   for (int i = 0; i < 5; i++) {
      signed_transaction trx;
      trx.actions.emplace_back( vector<permission_level>{{N(asserter),config::active_name}},
                                provereset {} );

      set_tapos( trx );
      trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() );
144
      push_transaction( trx );
145 146 147 148 149 150 151 152
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
      BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status);
   }

} FC_LOG_AND_RETHROW() /// prove_mem_reset

153 154 155 156 157 158
/**
 * Prove the modifications to global variables are wiped between runs
 */
BOOST_FIXTURE_TEST_CASE( abi_from_variant, tester ) try {
   produce_blocks(2);

159
   create_accounts( {N(asserter)} );
160 161 162 163 164 165 166 167 168 169
   produce_block();

   set_code(N(asserter), asserter_wast);
   set_abi(N(asserter), asserter_abi);
   produce_blocks(1);

   auto resolver = [&,this]( const account_name& name ) -> optional<abi_serializer> {
      try {
         const auto& accnt  = this->control->get_database().get<account_object,by_name>( name );
         abi_def abi;
170
         if (abi_serializer::to_abi(accnt.abi, abi)) {
171 172 173 174 175 176 177 178 179
            return abi_serializer(abi);
         }
         return optional<abi_serializer>();
      } FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name))
   };

   variant pretty_trx = mutable_variant_object()
      ("actions", variants({
         mutable_variant_object()
B
Bart Wyatt 已提交
180
            ("account", "asserter")
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
            ("name", "procassert")
            ("authorization", variants({
               mutable_variant_object()
                  ("actor", "asserter")
                  ("permission", name(config::active_name).to_string())
            }))
            ("data", mutable_variant_object()
               ("condition", 1)
               ("message", "Should Not Assert!")
            )
         })
      );

   signed_transaction trx;
   abi_serializer::from_variant(pretty_trx, trx, resolver);
   set_tapos( trx );
   trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() );
198
   push_transaction( trx );
199 200 201 202 203 204 205
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
   const auto& receipt = get_transaction_receipt(trx.id());
   BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status);

} FC_LOG_AND_RETHROW() /// prove_mem_reset

206
// test softfloat 32 bit operations
207
BOOST_FIXTURE_TEST_CASE( f32_tests, tester ) try {
B
Bucky Kittinger 已提交
208 209
   produce_blocks(2);

210
   create_accounts( {N(f32_tests)} );
B
Bucky Kittinger 已提交
211
   produce_block();
212 213 214
   {
      set_code(N(f32_tests), f32_test_wast);
      produce_blocks(10);
B
Bucky Kittinger 已提交
215

216 217 218 219 220 221
      signed_transaction trx;
      action act;
      act.account = N(f32_tests);
      act.name = N();
      act.authorization = vector<permission_level>{{N(f32_tests),config::active_name}};
      trx.actions.push_back(act);
B
Bucky Kittinger 已提交
222

223 224 225 226 227 228 229 230 231 232
      set_tapos(trx);
      trx.sign(get_private_key( N(f32_tests), "active" ), chain_id_type());
      push_transaction(trx);
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
   }
   {
      set_code(N(f32_tests), f32_bitwise_test_wast);
      produce_blocks(10);
B
Bucky Kittinger 已提交
233

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
      signed_transaction trx;
      action act;
      act.account = N(f32_tests);
      act.name = N();
      act.authorization = vector<permission_level>{{N(f32_tests),config::active_name}};
      trx.actions.push_back(act);

      set_tapos(trx);
      trx.sign(get_private_key( N(f32_tests), "active" ), chain_id_type());
      push_transaction(trx);
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
   }
   {
      set_code(N(f32_tests), f32_cmp_test_wast);
      produce_blocks(10);

      signed_transaction trx;
      action act;
      act.account = N(f32_tests);
      act.name = N();
      act.authorization = vector<permission_level>{{N(f32_tests),config::active_name}};
      trx.actions.push_back(act);

      set_tapos(trx);
      trx.sign(get_private_key( N(f32_tests), "active" ), chain_id_type());
      push_transaction(trx);
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
   }
} FC_LOG_AND_RETHROW()

// test softfloat 64 bit operations
BOOST_FIXTURE_TEST_CASE( f64_tests, tester ) try {
   produce_blocks(2);

   create_accounts( {N(f_tests)} );
   produce_block();
   {
      set_code(N(f_tests), f64_test_wast);
      produce_blocks(10);

      signed_transaction trx;
      action act;
      act.account = N(f_tests);
      act.name = N();
      act.authorization = vector<permission_level>{{N(f_tests),config::active_name}};
      trx.actions.push_back(act);

      set_tapos(trx);
      trx.sign(get_private_key( N(f_tests), "active" ), chain_id_type());
      push_transaction(trx);
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
   }
   {
      set_code(N(f_tests), f64_bitwise_test_wast);
      produce_blocks(10);

      signed_transaction trx;
      action act;
      act.account = N(f_tests);
      act.name = N();
      act.authorization = vector<permission_level>{{N(f_tests),config::active_name}};
      trx.actions.push_back(act);

      set_tapos(trx);
      trx.sign(get_private_key( N(f_tests), "active" ), chain_id_type());
      push_transaction(trx);
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
   }
   {
      set_code(N(f_tests), f64_cmp_test_wast);
      produce_blocks(10);

      signed_transaction trx;
      action act;
      act.account = N(f_tests);
      act.name = N();
      act.authorization = vector<permission_level>{{N(f_tests),config::active_name}};
      trx.actions.push_back(act);

      set_tapos(trx);
      trx.sign(get_private_key( N(f_tests), "active" ), chain_id_type());
      push_transaction(trx);
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
   }
} FC_LOG_AND_RETHROW()

B
Bucky Kittinger 已提交
330
#if 0
331 332 333 334 335 336 337
// test softfloat conversion operations
BOOST_FIXTURE_TEST_CASE( f32_f64_conversion_tests, tester ) try {
   produce_blocks(2);

   create_accounts( {N(f_tests)} );
   produce_block();
   {
B
Bucky Kittinger 已提交
338
      set_code(N(f_tests), f32_f64_conv_wast);
339
      produce_blocks(10);
B
Bucky Kittinger 已提交
340

341 342 343 344 345 346 347 348 349 350 351 352 353 354
      signed_transaction trx;
      action act;
      act.account = N(f_tests);
      act.name = N();
      act.authorization = vector<permission_level>{{N(f_tests),config::active_name}};
      trx.actions.push_back(act);

      set_tapos(trx);
      trx.sign(get_private_key( N(f_tests), "active" ), chain_id_type());
      push_transaction(trx);
      produce_blocks(1);
      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
      const auto& receipt = get_transaction_receipt(trx.id());
   }
B
Bucky Kittinger 已提交
355
} FC_LOG_AND_RETHROW()
B
Bucky Kittinger 已提交
356
#endif
357

358
/**
359
 * Make sure WASM "start" method is used correctly
360 361 362 363
 */
BOOST_FIXTURE_TEST_CASE( check_entry_behavior, tester ) try {
   produce_blocks(2);

364
   create_accounts( {N(entrycheck)} );
365 366 367 368 369 370 371
   produce_block();

   set_code(N(entrycheck), entry_wast);
   produce_blocks(10);

   signed_transaction trx;
   action act;
372
   act.account = N(entrycheck);
373 374 375 376 377 378
   act.name = N();
   act.authorization = vector<permission_level>{{N(entrycheck),config::active_name}};
   trx.actions.push_back(act);

   set_tapos(trx);
   trx.sign(get_private_key( N(entrycheck), "active" ), chain_id_type());
379
   push_transaction(trx);
380 381 382 383
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
   const auto& receipt = get_transaction_receipt(trx.id());
   BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status);
384 385 386 387 388 389 390 391
} FC_LOG_AND_RETHROW()

/**
 * Ensure we can load a wasm w/o memory
 */
BOOST_FIXTURE_TEST_CASE( simple_no_memory_check, tester ) try {
   produce_blocks(2);

392
   create_accounts( {N(nomem)} );
393 394 395 396 397 398 399 400
   produce_block();

   set_code(N(nomem), simple_no_memory_wast);
   produce_blocks(1);

   //the apply func of simple_no_memory_wast tries to call a native func with linear memory pointer
   signed_transaction trx;
   action act;
401
   act.account = N(nomem);
402 403 404 405 406
   act.name = N();
   act.authorization = vector<permission_level>{{N(nomem),config::active_name}};
   trx.actions.push_back(act);

   trx.sign(get_private_key( N(nomem), "active" ), chain_id_type());
407
   BOOST_CHECK_THROW(push_transaction( trx ), wasm_execution_error);
408
} FC_LOG_AND_RETHROW()
409

410 411 412 413
//Make sure globals are all reset to their inital values
BOOST_FIXTURE_TEST_CASE( check_global_reset, tester ) try {
   produce_blocks(2);

414
   create_accounts( {N(globalreset)} );
415 416 417 418 419 420
   produce_block();

   set_code(N(globalreset), mutable_global_wast);
   produce_blocks(1);

   signed_transaction trx;
421
   {
422
   action act;
423
   act.account = N(globalreset);
K
Kevin Heifner 已提交
424
   act.name = name(0ULL);
425 426
   act.authorization = vector<permission_level>{{N(globalreset),config::active_name}};
   trx.actions.push_back(act);
427 428 429 430 431 432 433 434
   }
   {
   action act;
   act.account = N(globalreset);
   act.name = 1ULL;
   act.authorization = vector<permission_level>{{N(globalreset),config::active_name}};
   trx.actions.push_back(act);
   }
435 436 437

   set_tapos(trx);
   trx.sign(get_private_key( N(globalreset), "active" ), chain_id_type());
438
   push_transaction(trx);
439 440 441 442 443 444
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
   const auto& receipt = get_transaction_receipt(trx.id());
   BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status);
} FC_LOG_AND_RETHROW()

445
BOOST_FIXTURE_TEST_CASE( stl_test, tester ) try {
446
    produce_blocks(2);
447

448
    create_accounts( {N(stltest), N(alice), N(bob)} );
449 450 451 452 453 454 455 456
    produce_block();

    set_code(N(stltest), stltest_wast);
    set_abi(N(stltest), stltest_abi);
    produce_blocks(1);

    const auto& accnt  = control->get_database().get<account_object,by_name>( N(stltest) );
    abi_def abi;
457
    BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true);
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    abi_serializer abi_ser(abi);

    //send message
    {
        signed_transaction trx;
        action msg_act;
        msg_act.account = N(stltest);
        msg_act.name = N(message);
        msg_act.authorization = vector<permission_level>{{N(bob), config::active_name}};
        msg_act.data = abi_ser.variant_to_binary("message", mutable_variant_object()
                                             ("from", "bob")
                                             ("to", "alice")
                                             ("message","Hi Alice!")
                                             );
        trx.actions.push_back(std::move(msg_act));

        set_tapos(trx);
        trx.sign(get_private_key(N(bob), "active"), chain_id_type());
476
        push_transaction(trx);
477 478 479 480 481 482
        produce_block();

        BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
    }
} FC_LOG_AND_RETHROW() /// stltest

483
//Make sure we can create a wasm with maximum pages, but not grow it any
484 485 486
BOOST_FIXTURE_TEST_CASE( big_memory, tester ) try {
   produce_blocks(2);

487
   create_accounts( {N(bigmem)} );
488 489
   produce_block();

490
   string biggest_memory_wast_f = fc::format_string(biggest_memory_wast, fc::mutable_variant_object(
491
                                          "MAX_WASM_PAGES", eosio::chain::wasm_constraints::maximum_linear_memory/(64*1024)));
492

493
   set_code(N(bigmem), biggest_memory_wast_f.c_str());
494 495 496 497 498 499 500 501 502 503 504
   produce_blocks(1);

   signed_transaction trx;
   action act;
   act.account = N(bigmem);
   act.name = N();
   act.authorization = vector<permission_level>{{N(bigmem),config::active_name}};
   trx.actions.push_back(act);

   set_tapos(trx);
   trx.sign(get_private_key( N(bigmem), "active" ), chain_id_type());
505
   //but should not be able to grow beyond largest page
M
Matt Witherspoon 已提交
506
   push_transaction(trx);
507 508 509

   produce_blocks(1);

510 511 512
   string too_big_memory_wast_f = fc::format_string(too_big_memory_wast, fc::mutable_variant_object(
                                          "MAX_WASM_PAGES_PLUS_ONE", eosio::chain::wasm_constraints::maximum_linear_memory/(64*1024)+1));
   BOOST_CHECK_THROW(set_code(N(bigmem), too_big_memory_wast_f.c_str()), eosio::chain::wasm_execution_error);
513 514 515 516 517 518

} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE( table_init_tests, tester ) try {
   produce_blocks(2);

519
   create_accounts( {N(tableinit)} );
520 521 522 523 524 525 526 527 528 529 530 531
   produce_block();

   set_code(N(tableinit), valid_sparse_table);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(tableinit), too_big_table), eosio::chain::wasm_execution_error);

} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE( memory_init_border, tester ) try {
   produce_blocks(2);

532
   create_accounts( {N(memoryborder)} );
533 534 535 536 537 538 539 540 541 542 543
   produce_block();

   set_code(N(memoryborder), memory_init_borderline);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(memoryborder), memory_init_toolong), eosio::chain::wasm_execution_error);
   BOOST_CHECK_THROW(set_code(N(memoryborder), memory_init_negative), eosio::chain::wasm_execution_error);

} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE( imports, tester ) try {
D
Daniel Larimer 已提交
544 545
   try {
      produce_blocks(2);
546

D
Daniel Larimer 已提交
547 548
      create_accounts( {N(imports)} );
      produce_block();
549

D
Daniel Larimer 已提交
550 551 552 553 554 555 556 557
      //this will fail to link but that's okay; mainly looking to make sure that the constraint
      // system doesn't choke when memories and tables exist only as imports
      BOOST_CHECK_THROW(set_code(N(imports), memory_table_import), fc::exception);
   } catch ( const fc::exception& e ) {

        edump((e.to_detail_string()));
        throw;
   }
558 559 560 561 562 563

} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE( lotso_globals, tester ) try {
   produce_blocks(2);

564
   create_accounts( {N(globals)} );
565 566 567
   produce_block();

   std::stringstream ss;
568
   ss << "(module (export \"apply\" (func $apply)) (func $apply (param $0 i64) (param $1 i64))";
569 570 571 572 573 574
   for(unsigned int i = 0; i < 85; ++i)
      ss << "(global $g" << i << " (mut i32) (i32.const 0))" << "(global $g" << i+100 << " (mut i64) (i64.const 0))";
   //that gives us 1020 bytes of mutable globals
   //add a few immutable ones for good measure
   for(unsigned int i = 0; i < 10; ++i)
      ss << "(global $g" << i+200 << " i32 (i32.const 0))";
A
arhag 已提交
575

576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
   set_code(N(globals),
      string(ss.str() + ")")
   .c_str());
   //1024 should pass
   set_code(N(globals),
      string(ss.str() + "(global $z (mut i32) (i32.const -12)))")
   .c_str());
   //1028 should fail
   BOOST_CHECK_THROW(set_code(N(globals),
      string(ss.str() + "(global $z (mut i64) (i64.const -12)))")
   .c_str()), eosio::chain::wasm_execution_error);;

} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE( offset_check, tester ) try {
   produce_blocks(2);

593
   create_accounts( {N(offsets)} );
594 595 596
   produce_block();

   vector<string> loadops = {
597
      "i32.load", "i64.load", "f32.load", "f64.load", "i32.load8_s", "i32.load8_u",
598 599 600 601 602 603
      "i32.load16_s", "i32.load16_u", "i64.load8_s", "i64.load8_u", "i64.load16_s",
      "i64.load16_u", "i64.load32_s", "i64.load32_u"
   };
   vector<vector<string>> storeops = {
      {"i32.store",   "i32"},
      {"i64.store",   "i64"},
604 605
      {"f32.store",   "f32"},
      {"f64.store",   "f64"},
606 607 608 609 610 611 612 613 614
      {"i32.store8",  "i32"},
      {"i32.store16", "i32"},
      {"i64.store8",  "i64"},
      {"i64.store16", "i64"},
      {"i64.store32", "i64"},
   };

   for(const string& s : loadops) {
      std::stringstream ss;
615 616
      ss << "(module (memory $0 " << eosio::chain::wasm_constraints::maximum_linear_memory/(64*1024) << ") (func $apply (param $0 i64) (param $1 i64) ";
      ss << "(drop (" << s << " offset=" << eosio::chain::wasm_constraints::maximum_linear_memory-2 << " (i32.const 0)))";
617
      ss << ") (export \"apply\" (func $apply)) )";
618 619 620 621 622 623

      set_code(N(offsets), ss.str().c_str());
      produce_block();
   }
   for(const vector<string>& o : storeops) {
      std::stringstream ss;
624 625
      ss << "(module (memory $0 " << eosio::chain::wasm_constraints::maximum_linear_memory/(64*1024) << ") (func $apply (param $0 i64) (param $1 i64) ";
      ss << "(" << o[0] << " offset=" << eosio::chain::wasm_constraints::maximum_linear_memory-2 << " (i32.const 0) (" << o[1] << ".const 0))";
626
      ss << ") (export \"apply\" (func $apply)) )";
627 628 629 630 631 632 633

      set_code(N(offsets), ss.str().c_str());
      produce_block();
   }

   for(const string& s : loadops) {
      std::stringstream ss;
634 635
      ss << "(module (memory $0 " << eosio::chain::wasm_constraints::maximum_linear_memory/(64*1024) << ") (func $apply (param $0 i64) (param $1 i64) ";
      ss << "(drop (" << s << " offset=" << eosio::chain::wasm_constraints::maximum_linear_memory+4 << " (i32.const 0)))";
636
      ss << ") (export \"apply\" (func $apply)) )";
637 638 639 640 641 642

      BOOST_CHECK_THROW(set_code(N(offsets), ss.str().c_str()), eosio::chain::wasm_execution_error);
      produce_block();
   }
   for(const vector<string>& o : storeops) {
      std::stringstream ss;
643 644
      ss << "(module (memory $0 " << eosio::chain::wasm_constraints::maximum_linear_memory/(64*1024) << ") (func $apply (param $0 i64) (param $1 i64) ";
      ss << "(" << o[0] << " offset=" << eosio::chain::wasm_constraints::maximum_linear_memory+4 << " (i32.const 0) (" << o[1] << ".const 0))";
645
      ss << ") (export \"apply\" (func $apply)) )";
646 647 648 649 650 651 652

      BOOST_CHECK_THROW(set_code(N(offsets), ss.str().c_str()), eosio::chain::wasm_execution_error);
      produce_block();
   }

} FC_LOG_AND_RETHROW()

653

K
Khaled Al-Hassanieh 已提交
654 655
BOOST_FIXTURE_TEST_CASE(noop, tester) try {
   produce_blocks(2);
656
   create_accounts( {N(noop), N(alice)} );
K
Khaled Al-Hassanieh 已提交
657 658 659
   produce_block();

   set_code(N(noop), noop_wast);
D
Daniel Larimer 已提交
660

K
Khaled Al-Hassanieh 已提交
661 662 663
   set_abi(N(noop), noop_abi);
   const auto& accnt  = control->get_database().get<account_object,by_name>(N(noop));
   abi_def abi;
664
   BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true);
K
Khaled Al-Hassanieh 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
   abi_serializer abi_ser(abi);

   {
      produce_blocks(5);
      signed_transaction trx;
      action act;
      act.account = N(noop);
      act.name = N(anyaction);
      act.authorization = vector<permission_level>{{N(noop), config::active_name}};

      act.data = abi_ser.variant_to_binary("anyaction", mutable_variant_object()
                                           ("from", "noop")
                                           ("type", "some type")
                                           ("data", "some data goes here")
                                           );

      trx.actions.emplace_back(std::move(act));

      set_tapos(trx);
      trx.sign(get_private_key(N(noop), "active"), chain_id_type());
K
Khaled Al-Hassanieh 已提交
685
      push_transaction(trx);
K
Khaled Al-Hassanieh 已提交
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
      produce_block();

      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
   }

   {
      produce_blocks(5);
      signed_transaction trx;
      action act;
      act.account = N(noop);
      act.name = N(anyaction);
      act.authorization = vector<permission_level>{{N(alice), config::active_name}};

      act.data = abi_ser.variant_to_binary("anyaction", mutable_variant_object()
                                           ("from", "alice")
                                           ("type", "some type")
                                           ("data", "some data goes here")
                                           );

      trx.actions.emplace_back(std::move(act));

      set_tapos(trx);
      trx.sign(get_private_key(N(alice), "active"), chain_id_type());
K
Khaled Al-Hassanieh 已提交
709
      push_transaction(trx);
K
Khaled Al-Hassanieh 已提交
710 711 712 713 714 715 716
      produce_block();

      BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
   }

 } FC_LOG_AND_RETHROW()

717 718 719 720 721 722 723 724 725 726 727 728
// abi_serializer::to_variant failed because eosio_system_abi modified via set_abi.
// This test also verifies that chain_initializer::eos_contract_abi() does not conflict
// with eosio_system_abi as they are not allowed to contain duplicates.
BOOST_FIXTURE_TEST_CASE(eosio_abi, tester) try {
   produce_blocks(2);

   set_code(config::system_account_name, eosio_system_wast);
   set_abi(config::system_account_name, eosio_system_abi);
   produce_block();

   const auto& accnt  = control->get_database().get<account_object,by_name>(config::system_account_name);
   abi_def abi;
729
   BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true);
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
   abi_serializer abi_ser(abi);
   abi_ser.validate();

   signed_transaction trx;
   name a = N(alice);
   authority owner_auth =  authority( get_public_key( a, "owner" ) );
   trx.actions.emplace_back( vector<permission_level>{{config::system_account_name,config::active_name}},
                             contracts::newaccount{
                                   .creator  = config::system_account_name,
                                   .name     = a,
                                   .owner    = owner_auth,
                                   .active   = authority( get_public_key( a, "active" ) ),
                                   .recovery = authority( get_public_key( a, "recovery" ) ),
                             });
   set_tapos(trx);
   trx.sign( get_private_key( config::system_account_name, "active" ), chain_id_type()  );
   auto result = push_transaction( trx );

   fc::variant pretty_output;
   // verify to_variant works on eos native contract type: newaccount
   // see abi_serializer::to_abi()
   abi_serializer::to_variant(result, pretty_output, get_resolver());

   BOOST_TEST(fc::json::to_string(pretty_output).find("newaccount") != std::string::npos);

   produce_block();
} FC_LOG_AND_RETHROW()

B
Brian Johnson 已提交
758 759 760
BOOST_FIXTURE_TEST_CASE( test_table_key_validation, tester ) try {
} FC_LOG_AND_RETHROW()

M
Matt Witherspoon 已提交
761 762 763
BOOST_FIXTURE_TEST_CASE( check_table_maximum, tester ) try {
   produce_blocks(2);

764
   create_accounts( {N(tbl)} );
M
Matt Witherspoon 已提交
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
   produce_block();

   set_code(N(tbl), table_checker_wast);
   produce_blocks(1);
   {
   signed_transaction trx;
   action act;
   act.name = 555ULL<<32 | 0ULL;       //top 32 is what we assert against, bottom 32 is indirect call index
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());
   push_transaction(trx);
   }

   produce_blocks(1);

   {
   signed_transaction trx;
   action act;
   act.name = 555ULL<<32 | 1022ULL;       //top 32 is what we assert against, bottom 32 is indirect call index
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());
   push_transaction(trx);
   }

   produce_blocks(1);

   {
   signed_transaction trx;
   action act;
   act.name = 7777ULL<<32 | 1023ULL;       //top 32 is what we assert against, bottom 32 is indirect call index
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());
   push_transaction(trx);
   }

   produce_blocks(1);

   {
   signed_transaction trx;
   action act;
   act.name = 7778ULL<<32 | 1023ULL;       //top 32 is what we assert against, bottom 32 is indirect call index
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());

   //should fail, a check to make sure assert() in wasm is being evaluated correctly
   BOOST_CHECK_THROW(push_transaction(trx), fc::assert_exception);
   }

   produce_blocks(1);

   {
   signed_transaction trx;
   action act;
   act.name = 133ULL<<32 | 5ULL;       //top 32 is what we assert against, bottom 32 is indirect call index
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());

   //should fail, this element index (5) does not exist
   BOOST_CHECK_THROW(push_transaction(trx), eosio::chain::wasm_execution_error);
   }

   produce_blocks(1);

   {
   signed_transaction trx;
   action act;
   act.name = eosio::chain::wasm_constraints::maximum_table_elements+54334;
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());

   //should fail, this element index is out of range
   BOOST_CHECK_THROW(push_transaction(trx), eosio::chain::wasm_execution_error);
   }

   produce_blocks(1);

859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
   //run a few tests with new, proper syntax, call_indirect
   set_code(N(tbl), table_checker_proper_syntax_wast);
   produce_blocks(1);

   {
   signed_transaction trx;
   action act;
   act.name = 555ULL<<32 | 1022ULL;       //top 32 is what we assert against, bottom 32 is indirect call index
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());
   push_transaction(trx);
   }

   produce_blocks(1);
B
Bucky Kittinger 已提交
876
#if 0
877 878 879 880 881 882 883 884 885 886 887
   {
   signed_transaction trx;
   action act;
   act.name = 7777ULL<<32 | 1023ULL;       //top 32 is what we assert against, bottom 32 is indirect call index
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());
   push_transaction(trx);
   }
M
Matt Witherspoon 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900 901
   set_code(N(tbl), table_checker_small_wast);
   produce_blocks(1);

   {
   signed_transaction trx;
   action act;
   act.name = 888ULL;
   act.account = N(tbl);
   act.authorization = vector<permission_level>{{N(tbl),config::active_name}};
   trx.actions.push_back(act);
   set_tapos(trx);
   trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());

   //an element that is out of range and has no mmap access permission either (should be a trapped segv)
902
   BOOST_CHECK_EXCEPTION(push_transaction(trx), eosio::chain::wasm_execution_error, [](const eosio::chain::wasm_execution_error &e) {return true;});
M
Matt Witherspoon 已提交
903
   }
B
Bucky Kittinger 已提交
904
#endif
M
Matt Witherspoon 已提交
905 906 907

} FC_LOG_AND_RETHROW()

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
BOOST_FIXTURE_TEST_CASE( protected_globals, tester ) try {
   produce_blocks(2);

   create_accounts( {N(gob)} );
   produce_block();

   BOOST_CHECK_THROW(set_code(N(gob), global_protection_none_get_wast), fc::exception);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(gob), global_protection_some_get_wast), fc::exception);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(gob), global_protection_none_set_wast), fc::exception);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(gob), global_protection_some_set_wast), fc::exception);
   produce_blocks(1);

   //sanity to make sure I got general binary construction okay
   set_code(N(gob), global_protection_okay_get_wasm);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(gob), global_protection_none_get_wasm), fc::exception);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(gob), global_protection_some_get_wasm), fc::exception);
   produce_blocks(1);

   set_code(N(gob), global_protection_okay_set_wasm);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(gob), global_protection_some_set_wasm), fc::exception);
   produce_blocks(1);
} FC_LOG_AND_RETHROW()

943 944 945 946 947 948 949 950 951
BOOST_FIXTURE_TEST_CASE( lotso_stack, tester ) try {
   produce_blocks(2);

   create_accounts( {N(stackz)} );
   produce_block();

   {
   std::stringstream ss;
   ss << "(module ";
952 953
   ss << "(export \"apply\" (func $apply))";
   ss << "  (func $apply  (param $0 i64) (param $1 i64))";
954 955 956 957 958 959 960 961 962 963 964
   ss << "  (func ";
   for(unsigned int i = 0; i < wasm_constraints::maximum_func_local_bytes; i+=4)
      ss << "(local i32)";
   ss << "  )";
   ss << ")";
   set_code(N(stackz), ss.str().c_str());
   produce_blocks(1);
   }
   {
   std::stringstream ss;
   ss << "(module ";
965 966
   ss << "(export \"apply\" (func $apply))";
   ss << "  (func $apply  (param $0 i64) (param $1 i64))";
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
   ss << "  (func ";
   for(unsigned int i = 0; i < wasm_constraints::maximum_func_local_bytes; i+=8)
      ss << "(local f64)";
   ss << "  )";
   ss << ")";
   set_code(N(stackz), ss.str().c_str());
   produce_blocks(1);
   }

   //try to use contract with this many locals (so that it actually gets compiled). Note that
   //at this time not having an apply() is an acceptable non-error.
   {
   signed_transaction trx;
   action act;
   act.account = N(stackz);
   act.name = N();
   act.authorization = vector<permission_level>{{N(stackz),config::active_name}};
   trx.actions.push_back(act);

   set_tapos(trx);
   trx.sign(get_private_key( N(stackz), "active" ), chain_id_type());
   push_transaction(trx);
   }


   //too many locals! should fail validation
   {
   std::stringstream ss;
   ss << "(module ";
996 997
   ss << "(export \"apply\" (func $apply))";
   ss << "  (func $apply  (param $0 i64) (param $1 i64))";
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
   ss << "  (func ";
   for(unsigned int i = 0; i < wasm_constraints::maximum_func_local_bytes+4; i+=4)
      ss << "(local i32)";
   ss << "  )";
   ss << ")";
   BOOST_CHECK_THROW(set_code(N(stackz), ss.str().c_str()), fc::exception);
   produce_blocks(1);
   }

   //try again but with parameters
   {
   std::stringstream ss;
   ss << "(module ";
1011 1012
   ss << "(export \"apply\" (func $apply))";
   ss << "  (func $apply  (param $0 i64) (param $1 i64))";
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
   ss << "  (func ";
   for(unsigned int i = 0; i < wasm_constraints::maximum_func_local_bytes; i+=4)
      ss << "(param i32)";
   ss << "  )";
   ss << ")";
   set_code(N(stackz), ss.str().c_str());
   produce_blocks(1);
   }
   //try to use contract with this many params
   {
   signed_transaction trx;
   action act;
   act.account = N(stackz);
   act.name = N();
   act.authorization = vector<permission_level>{{N(stackz),config::active_name}};
   trx.actions.push_back(act);

   set_tapos(trx);
   trx.sign(get_private_key( N(stackz), "active" ), chain_id_type());
   push_transaction(trx);
   }

   //too many params!
   {
   std::stringstream ss;
   ss << "(module ";
1039 1040
   ss << "(export \"apply\" (func $apply))";
   ss << "  (func $apply  (param $0 i64) (param $1 i64))";
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
   ss << "  (func ";
   for(unsigned int i = 0; i < wasm_constraints::maximum_func_local_bytes+4; i+=4)
      ss << "(param i32)";
   ss << "  )";
   ss << ")";
   BOOST_CHECK_THROW(set_code(N(stackz), ss.str().c_str()), fc::exception);
   produce_blocks(1);
   }

   //let's mix params and locals are make sure it's counted correctly in mixed case
   {
   std::stringstream ss;
   ss << "(module ";
1054 1055
   ss << "(export \"apply\" (func $apply))";
   ss << "  (func $apply  (param $0 i64) (param $1 i64))";
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
   ss << "  (func (param i64) (param f32) ";
   for(unsigned int i = 12; i < wasm_constraints::maximum_func_local_bytes; i+=4)
      ss << "(local i32)";
   ss << "  )";
   ss << ")";
   set_code(N(stackz), ss.str().c_str());
   produce_blocks(1);
   }
   {
   std::stringstream ss;
   ss << "(module ";
1067 1068
   ss << "(export \"apply\" (func $apply))";
   ss << "  (func $apply  (param $0 i64) (param $1 i64))";
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
   ss << "  (func (param i64) (param f32) ";
   for(unsigned int i = 12; i < wasm_constraints::maximum_func_local_bytes+4; i+=4)
      ss << "(local f32)";
   ss << "  )";
   ss << ")";
   BOOST_CHECK_THROW(set_code(N(stackz), ss.str().c_str()), fc::exception);
   produce_blocks(1);
   }


} FC_LOG_AND_RETHROW()

1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
BOOST_FIXTURE_TEST_CASE( apply_export_and_signature, tester ) try {
   produce_blocks(2);

   create_accounts( {N(bbb)} );
   produce_block();

   BOOST_CHECK_THROW(set_code(N(bbb), no_apply_wast), fc::exception);
   produce_blocks(1);

   BOOST_CHECK_THROW(set_code(N(bbb), apply_wrong_signature_wast), fc::exception);
   produce_blocks(1);
} FC_LOG_AND_RETHROW()

1094
BOOST_AUTO_TEST_SUITE_END()