hermez-node/test/zkproof/zkproof_test.go
test/zkproof/zkproof_test.goRaw
1package zkproof
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io/ioutil"
8 "os"
9 "testing"
10 "time"
11
12 "github.com/hermeznetwork/hermez-node/common"
13 "github.com/hermeznetwork/hermez-node/db/statedb"
14 "github.com/hermeznetwork/hermez-node/prover"
15 "github.com/hermeznetwork/hermez-node/test/til"
16 "github.com/hermeznetwork/hermez-node/test/txsets"
17 "github.com/hermeznetwork/hermez-node/txprocessor"
18 "github.com/stretchr/testify/assert"
19 "github.com/stretchr/testify/require"
20)
21
22var proofServerURL string
23
24const pollInterval = 200 * time.Millisecond
25
26func TestMain(m *testing.M) {
27 exitVal := 0
28 proofServerURL = os.Getenv("PROOF_SERVER_URL")
29 if proofServerURL != "" {
30 exitVal = m.Run()
31 }
32 os.Exit(exitVal)
33}
34
35const MaxTx = 376
36const NLevels = 32
37const MaxL1Tx = 256
38const MaxFeeTx = 64
39const ChainID uint16 = 1
40
41var config = txprocessor.Config{
42 NLevels: uint32(NLevels),
43 MaxTx: MaxTx,
44 MaxL1Tx: MaxL1Tx,
45 MaxFeeTx: MaxFeeTx,
46 ChainID: ChainID,
47}
48
49func initStateDB(t *testing.T) *statedb.StateDB {
50 dir, err := ioutil.TempDir("", "tmpdb")
51 require.NoError(t, err)
52 defer assert.Nil(t, os.RemoveAll(dir))
53
54 sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, NLevels)
55 require.NoError(t, err)
56 return sdb
57}
58
59func sendProofAndCheckResp(t *testing.T, ptOut *txprocessor.ProcessTxOutput) {
60 // Store zkinputs json for debugging purposes
61 zkInputsJSON, err := json.Marshal(ptOut.ZKInputs)
62 require.NoError(t, err)
63 err = ioutil.WriteFile("/tmp/dbgZKInputs.json", zkInputsJSON, 0640) //nolint:gosec
64 require.NoError(t, err)
65
66 proofServerClient := prover.NewProofServerClient(proofServerURL, pollInterval)
67 err = proofServerClient.WaitReady(context.Background())
68 require.NoError(t, err)
69 err = proofServerClient.CalculateProof(context.Background(), ptOut.ZKInputs)
70 require.NoError(t, err)
71 proof, pubInputs, err := proofServerClient.GetProof(context.Background())
72 require.NoError(t, err)
73 fmt.Printf("proof: %#v\n", proof)
74 fmt.Printf("pubInputs: %#v\n", pubInputs)
75}
76
77func TestZKInputsEmpty(t *testing.T) {
78 sdb := initStateDB(t)
79
80 tp := txprocessor.NewTxProcessor(sdb, config)
81
82 coordIdxs := []common.Idx{}
83 l1UserTxs := []common.L1Tx{}
84 l1CoordTxs := []common.L1Tx{}
85 l2Txs := []common.PoolL2Tx{}
86 ptOut, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
87 require.NoError(t, err)
88
89 sendProofAndCheckResp(t, ptOut) // test empty batch ZKInputs
90
91 _, coordIdxs, l1UserTxs, l1CoordTxs, l2Txs = txsets.GenerateTxsZKInputs0(t, ChainID)
92
93 _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
94 require.NoError(t, err)
95
96 coordIdxs = []common.Idx{}
97 l1UserTxs = []common.L1Tx{}
98 l1CoordTxs = []common.L1Tx{}
99 l2Txs = []common.PoolL2Tx{}
100 ptOut, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
101 require.NoError(t, err)
102 sendProofAndCheckResp(t, ptOut) // test empty batch ZKInputs after a non-empty batch
103}
104
105func TestZKInputs0(t *testing.T) {
106 sdb := initStateDB(t)
107
108 _, coordIdxs, l1UserTxs, l1CoordTxs, l2Txs := txsets.GenerateTxsZKInputs0(t, ChainID)
109
110 tp := txprocessor.NewTxProcessor(sdb, config)
111 ptOut, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
112 require.NoError(t, err)
113
114 sendProofAndCheckResp(t, ptOut)
115}
116func TestZKInputs1(t *testing.T) {
117 sdb := initStateDB(t)
118
119 _, coordIdxs, l1UserTxs, l1CoordTxs, l2Txs := txsets.GenerateTxsZKInputs1(t, ChainID)
120
121 tp := txprocessor.NewTxProcessor(sdb, config)
122 ptOut, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
123 require.NoError(t, err)
124
125 sendProofAndCheckResp(t, ptOut)
126}
127func TestZKInputs2(t *testing.T) {
128 sdb := initStateDB(t)
129
130 _, coordIdxs, l1UserTxs, l1CoordTxs, l2Txs := txsets.GenerateTxsZKInputs2(t, ChainID)
131
132 tp := txprocessor.NewTxProcessor(sdb, config)
133 ptOut, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
134 require.NoError(t, err)
135
136 sendProofAndCheckResp(t, ptOut)
137}
138func TestZKInputs3(t *testing.T) {
139 sdb := initStateDB(t)
140
141 _, coordIdxs, l1UserTxs, l1CoordTxs, l2Txs := txsets.GenerateTxsZKInputs3(t, ChainID)
142
143 tp := txprocessor.NewTxProcessor(sdb, config)
144 ptOut, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
145 require.NoError(t, err)
146
147 sendProofAndCheckResp(t, ptOut)
148}
149func TestZKInputs4(t *testing.T) {
150 sdb := initStateDB(t)
151
152 _, coordIdxs, l1UserTxs, l1CoordTxs, l2Txs := txsets.GenerateTxsZKInputs4(t, ChainID)
153
154 tp := txprocessor.NewTxProcessor(sdb, config)
155 ptOut, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
156 require.NoError(t, err)
157
158 sendProofAndCheckResp(t, ptOut)
159}
160
161func TestZKInputs5(t *testing.T) {
162 sdb := initStateDB(t)
163
164 _, coordIdxs, l1UserTxs, l1CoordTxs, l2Txs := txsets.GenerateTxsZKInputs5(t, ChainID)
165
166 tp := txprocessor.NewTxProcessor(sdb, config)
167 ptOut, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
168 require.NoError(t, err)
169
170 sendProofAndCheckResp(t, ptOut)
171}
172
173func TestZKInputs6(t *testing.T) {
174 sdb := initStateDB(t)
175
176 tc := til.NewContext(ChainID, common.RollupConstMaxL1UserTx)
177 blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
178 require.NoError(t, err)
179
180 // restart nonces of TilContext, as will be set by generating directly
181 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
182 tc.RestartNonces()
183
184 tp := txprocessor.NewTxProcessor(sdb, config)
185 // batch1
186 ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
187 require.NoError(t, err)
188
189 sendProofAndCheckResp(t, ptOut)
190
191 // batch2
192 l1UserTxs := []common.L1Tx{}
193 l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
194 ptOut, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
195 require.NoError(t, err)
196
197 sendProofAndCheckResp(t, ptOut)
198
199 // batch3
200 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
201 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
202 ptOut, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
203 require.NoError(t, err)
204
205 sendProofAndCheckResp(t, ptOut)
206
207 // batch4
208 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
209 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[3].L2Txs)
210 ptOut, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[3].L1CoordinatorTxs, l2Txs)
211 require.NoError(t, err)
212
213 sendProofAndCheckResp(t, ptOut)
214
215 // batch5
216 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
217 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[4].L2Txs)
218 ptOut, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[4].L1CoordinatorTxs, l2Txs)
219 require.NoError(t, err)
220
221 sendProofAndCheckResp(t, ptOut)
222
223 // batch6
224 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
225 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[5].L2Txs)
226 ptOut, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[5].L1CoordinatorTxs, l2Txs)
227 require.NoError(t, err)
228
229 sendProofAndCheckResp(t, ptOut)
230
231 // batch7
232 // simulate the PoolL2Txs of the batch6
233 batchPoolL2 := `
234 Type: PoolL2
235 PoolTransferToEthAddr(1) A-B: 200 (126)
236 PoolTransferToEthAddr(0) B-C: 100 (126)`
237 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
238 require.NoError(t, err)
239
240 // Coordinator Idx where to send the fees
241 coordIdxs := []common.Idx{261, 262}
242 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
243 l2Txs = poolL2Txs
244 ptOut, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[6].L1CoordinatorTxs, l2Txs)
245 require.NoError(t, err)
246
247 sendProofAndCheckResp(t, ptOut)
248
249 // batch8
250 // simulate the PoolL2Txs of the batch7
251 batchPoolL2 = `
252 Type: PoolL2
253 PoolTransfer(0) A-B: 100 (126)
254 PoolTransfer(0) C-A: 50 (126)
255 PoolTransfer(1) B-C: 100 (126)
256 PoolExit(0) A: 100 (126)`
257 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
258 require.NoError(t, err)
259
260 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
261 l2Txs = poolL2Txs
262 ptOut, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[7].L1CoordinatorTxs, l2Txs)
263 require.NoError(t, err)
264
265 sendProofAndCheckResp(t, ptOut)
266
267 // batch9
268 // simulate the PoolL2Txs of the batch9
269 batchPoolL2 = `
270 Type: PoolL2
271 PoolTransfer(0) D-A: 300 (126)
272 PoolTransfer(0) B-D: 100 (126)`
273 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
274 require.NoError(t, err)
275
276 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
277 l2Txs = poolL2Txs
278 coordIdxs = []common.Idx{262}
279 ptOut, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
280 require.NoError(t, err)
281
282 sendProofAndCheckResp(t, ptOut)
283
284 // batch10
285 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
286 l2Txs = []common.PoolL2Tx{}
287 coordIdxs = []common.Idx{}
288 ptOut, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
289 require.NoError(t, err)
290
291 sendProofAndCheckResp(t, ptOut)
292}