Inspects the stack contents after a successful runTCO execution to verify anti-DOS properties: * 1. If 'checks' includes 'CHECK_EXEC', then check that all non-HIDDEN dag nodes were executed at least once. * 2. If 'checks' includes 'CHECK_CASE', then check that both branches of every CASE node were executed. * * If these are violated, it means that the dag had unpruned nodes. * * Returns 'SIM
| 532 | * dag_node dag[len]; |
| 533 | */ |
| 534 | static simplicity_err antiDos(flags_type checks, const call* stack, const dag_node* dag, size_t len) { |
| 535 | static_assert(CHECK_EXEC == FLAG_EXEC, "CHECK_EXEC does not match FLAG_EXEC"); |
| 536 | static_assert(CHECK_CASE == (FLAG_CASE_LEFT | FLAG_CASE_RIGHT), "CHECK_CASE does not match FLAG_CASE"); |
| 537 | simplicity_assert(CHECK_CASE == (checks & CHECK_CASE) || 0 == (checks & CHECK_CASE)); |
| 538 | |
| 539 | if (!checks) return SIMPLICITY_NO_ERROR; |
| 540 | |
| 541 | for(size_t i = 0; i < len; ++i) { |
| 542 | /* All non-HIDDEN nodes must be executed at least once. */ |
| 543 | /* Both branches of every case combinator must be executed at least once. */ |
| 544 | flags_type test_flags = (HIDDEN != dag[i].tag ? CHECK_EXEC : 0) |
| 545 | | (CASE == dag[i].tag ? CHECK_CASE : 0); |
| 546 | |
| 547 | /* Only enable requested checks */ |
| 548 | test_flags &= checks; |
| 549 | if (test_flags != (test_flags & stack[i].flags)) { |
| 550 | return SIMPLICITY_ERR_ANTIDOS; |
| 551 | } |
| 552 | } |
| 553 | |
| 554 | return SIMPLICITY_NO_ERROR; |
| 555 | } |
| 556 | |
| 557 | /* This structure is used by the static analysis that computes bounds on the working memory that suffices for |
| 558 | * the Simplicity interpreter, and the CPU cost bounds in milliWU |
no outgoing calls
no test coverage detected