MCPcopy Create free account
hub / github.com/ElementsProject/elements / simplicity_verifyCanonicalOrder

Function simplicity_verifyCanonicalOrder

src/simplicity/dag.c:380–469  ·  view source on GitHub ↗

Verifies that the 'dag' is in canonical order, meaning that nodes under the left branches have lower indices than nodes under * right branches, with the exception that nodes under right branches may (cross-)reference identical nodes that already occur under * left branches. * * Returns 'SIMPLICITY_NO_ERROR' if the 'dag' is in canonical order, and returns 'SIMPLICITY_ERR_DATA_OUT_OF_ORDER' if i

Source from the content-addressed store, hash-verified

378 * Precondition: dag_node dag[len] and 'dag' is well-formed.
379 */
380simplicity_err simplicity_verifyCanonicalOrder(dag_node* dag, const uint_fast32_t len) {
381 uint_fast32_t bottom = 0;
382 uint_fast32_t top = len-1; /* Underflow is checked below. */
383
384 if (!len) {
385 simplicity_assert(false); /* A well-formed dag has non-zero length */
386 return SIMPLICITY_NO_ERROR; /* However, an empty dag is technically in canonical order */
387 }
388
389 /* We use dag[i].aux as a "stack" to manage the traversal of the DAG. */
390 dag[top].aux = len; /* We will set top to 'len' to indicate we are finished. */
391
392 /* Each time any particular 'top' value is revisited in this loop, bottom has increased to be strictly larger than the last 'child'
393 value examined. Therefore we will make further progress in the loop the next time around.
394 By this reasoning any given 'top' value will be visited no more than numChildren(dag[top].tag) + 1 <= 3 times.
395 Thus this loop iterates at most O('len') times.
396 */
397 while (top < len) {
398 /* We determine canonical order by iterating through the dag in canonical (pre-)order,
399 incrementing 'bottom' each time we encounter a node that is (correctly) placed at the 'bottom' index.
400 We take advantage of the precondition that the dag is well-formed to know in advance that any children
401 of a node have index strictly less than the node itself.
402 */
403
404 /* Check first child. */
405 uint_fast32_t child = dag[top].child[0];
406 switch (dag[top].tag) {
407 case ASSERTL:
408 case ASSERTR:
409 case CASE:
410 case DISCONNECT:
411 case COMP:
412 case PAIR:
413 case INJL:
414 case INJR:
415 case TAKE:
416 case DROP:
417 if (bottom < child) {
418 dag[child].aux = top;
419 top = child;
420 continue;
421 }
422 if (bottom == child) bottom++;
423 case IDEN:
424 case UNIT:
425 case WITNESS:
426 case HIDDEN:
427 case JET:
428 case WORD:
429 break;
430 }
431
432 /* Check second child. */
433 child = dag[top].child[1];
434 switch (dag[top].tag) {
435 case ASSERTL:
436 case ASSERTR:
437 case CASE:

Callers 1

Calls

no outgoing calls

Tested by

no test coverage detected