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 }