github.com/consensys/gnark@v0.11.0/internal/regression_tests/issue1048/issue1048_test.go (about)

     1  package issue1048
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/consensys/gnark-crypto/ecc"
    10  	"github.com/consensys/gnark/constraint/solver"
    11  	"github.com/consensys/gnark/frontend"
    12  	"github.com/consensys/gnark/frontend/cs/r1cs"
    13  	"github.com/consensys/gnark/test"
    14  )
    15  
    16  var (
    17  	h1Unlocker chan struct{}
    18  	h2Unlocker chan struct{}
    19  )
    20  
    21  func HintControllable1(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
    22  	time.Sleep(100 * time.Millisecond)
    23  	for range h1Unlocker {
    24  	}
    25  	// add some sleep to this test to ensure that if there is parallelism, this
    26  	// hint returns second.
    27  	return fmt.Errorf("hint controllable 1")
    28  }
    29  
    30  func HintControllable2(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
    31  	for range h2Unlocker {
    32  	}
    33  	return fmt.Errorf("hint controllable 2")
    34  }
    35  
    36  type Circuit struct {
    37  	A frontend.Variable
    38  }
    39  
    40  func (c *Circuit) Define(api frontend.API) error {
    41  	_, err := api.Compiler().NewHint(HintControllable1, 1, c.A)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	// the solver groups currently instructions into group of 50. So there needs to be at least 50 instructions.
    46  	for i := 0; i < 50; i++ {
    47  		api.AssertIsEqual(c.A, c.A)
    48  	}
    49  	_, err = api.Compiler().NewHint(HintControllable2, 1, c.A)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	return nil
    55  }
    56  
    57  // TestTwoTasksOrder tests that when we run multiple tasks, then indeed they are
    58  // run in parallel. And if there is one task, then it indeed is one task (with
    59  // high probability).
    60  func TestTwoTasksOrder(t *testing.T) {
    61  	assert := test.NewAssert(t)
    62  
    63  	var circuit Circuit
    64  	ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
    65  	assert.NoError(err)
    66  	assignment := Circuit{A: 10}
    67  	wit, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
    68  	assert.NoError(err)
    69  	// case where second hint returns first
    70  	h1Unlocker = make(chan struct{})
    71  	h2Unlocker = make(chan struct{})
    72  	go func() {
    73  		h2Unlocker <- struct{}{}
    74  		close(h2Unlocker)
    75  		// let some time pass to ensure HintControllable2 returns first
    76  		time.Sleep(100 * time.Millisecond)
    77  		h1Unlocker <- struct{}{}
    78  		close(h1Unlocker)
    79  	}()
    80  	_, err = ccs.Solve(wit, solver.WithNbTasks(2), solver.WithHints(HintControllable1, HintControllable2))
    81  	assert.Equal(err.Error(), "hint controllable 2")
    82  
    83  	// case where first hint returns first
    84  	h1Unlocker = make(chan struct{})
    85  	h2Unlocker = make(chan struct{})
    86  	go func() {
    87  		h1Unlocker <- struct{}{}
    88  		close(h1Unlocker)
    89  		// let some time pass to ensure HintControllable1 returns first
    90  		time.Sleep(100 * time.Millisecond)
    91  		h2Unlocker <- struct{}{}
    92  		close(h2Unlocker)
    93  	}()
    94  	_, err = ccs.Solve(wit, solver.WithNbTasks(2), solver.WithHints(HintControllable1, HintControllable2))
    95  	assert.Equal(err.Error(), "hint controllable 1")
    96  
    97  	// with one task, the first hint always returns first. If not we get a deadlock (not tested here)
    98  	_, err = ccs.Solve(wit, solver.WithNbTasks(1), solver.WithHints(HintControllable1, HintControllable2))
    99  	assert.Equal(err.Error(), "hint controllable 1")
   100  }