Files
linea-monorepo/prover/circuits/pi-interconnection/e2e_test.go
AlexandreBelling c511121317 Prover: couple of fixes betav1 (#377)
* fix(execution): a few fixes in the wizard verifier

* feat(dict): pass the dict path from config

* fix: makeBw6Proof returns circuitID instead of -1

* fix(circuitID): make bw6Proof returns the circuitID

* fix(config-testing)

* feat(config): sepolia-full uses full aggregation

* style(naming): renaming the rolling hash fields and documenting the checks in pi-interconnection

* feat: flag for target number of constraints

* fix refactoring oversight

---------

Co-authored-by: Arya Tabaie <arya.pourtabatabaie@gmail.com>
2024-12-10 15:55:20 +01:00

293 lines
10 KiB
Go

//go:build !fuzzlight
package pi_interconnection_test
import (
"encoding/base64"
"fmt"
"slices"
"testing"
"github.com/stretchr/testify/require"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/test"
"github.com/consensys/linea-monorepo/prover/backend/aggregation"
"github.com/consensys/linea-monorepo/prover/backend/blobsubmission"
"github.com/consensys/linea-monorepo/prover/circuits/internal"
circuittesting "github.com/consensys/linea-monorepo/prover/circuits/internal/test_utils"
pi_interconnection "github.com/consensys/linea-monorepo/prover/circuits/pi-interconnection"
pitesting "github.com/consensys/linea-monorepo/prover/circuits/pi-interconnection/test_utils"
"github.com/consensys/linea-monorepo/prover/config"
blobtesting "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/v1/test_utils"
"github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy"
public_input "github.com/consensys/linea-monorepo/prover/public-input"
"github.com/consensys/linea-monorepo/prover/utils"
"github.com/stretchr/testify/assert"
)
// TODO test with random values instead of small ones
// some of the execution data are faked
func TestSingleBlockBlob(t *testing.T) {
testPI(t, pitesting.AssignSingleBlockBlob(t), withSlack(0, 2))
}
func TestSingleBlockBlobE2E(t *testing.T) {
req := pitesting.AssignSingleBlockBlob(t)
cfg := config.PublicInput{
MaxNbDecompression: len(req.Decompressions),
MaxNbExecution: len(req.Executions),
ExecutionMaxNbMsg: 1,
L2MsgMerkleDepth: 5,
L2MsgMaxNbMerkle: 1,
}
compiled, err := pi_interconnection.Compile(cfg, dummy.Compile)
assert.NoError(t, err)
a, err := compiled.Assign(req)
assert.NoError(t, err)
cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), scs.NewBuilder, compiled.Circuit, frontend.WithCapacity(3_000_000))
assert.NoError(t, err)
w, err := frontend.NewWitness(&a, ecc.BLS12_377.ScalarField())
assert.NoError(t, err)
assert.NoError(t, cs.IsSolved(w))
}
// some of the execution data are faked
func TestTinyTwoBatchBlob(t *testing.T) {
blob := blobtesting.TinyTwoBatchBlob(t)
const lastFinStateRootHash = 34
stateRootHashes := [3][32]byte{
internal.Uint64To32Bytes(lastFinStateRootHash),
internal.Uint64To32Bytes(23),
internal.Uint64To32Bytes(45),
}
execReq := []public_input.Execution{{
InitialBlockTimestamp: 6,
FinalStateRootHash: stateRootHashes[1],
FinalBlockNumber: 5,
FinalBlockTimestamp: 6,
LastRollingHashUpdate: internal.Uint64To32Bytes(7),
LastRollingHashUpdateNumber: 8,
FirstRollingHashUpdateNumber: 8,
L2MessageHashes: [][32]byte{internal.Uint64To32Bytes(3)},
InitialStateRootHash: stateRootHashes[0],
InitialBlockNumber: 5,
}, {
L2MessageHashes: [][32]byte{internal.Uint64To32Bytes(9)},
InitialBlockTimestamp: 7,
FinalStateRootHash: stateRootHashes[2],
FinalBlockNumber: 11,
FinalBlockTimestamp: 12,
LastRollingHashUpdate: internal.Uint64To32Bytes(13),
LastRollingHashUpdateNumber: 14,
FirstRollingHashUpdateNumber: 9,
InitialStateRootHash: stateRootHashes[1],
InitialBlockNumber: 6,
}}
blobReq := blobsubmission.Request{
Eip4844Enabled: true,
CompressedData: base64.StdEncoding.EncodeToString(blob),
ParentStateRootHash: utils.FmtIntHex32Bytes(lastFinStateRootHash),
FinalStateRootHash: utils.HexEncodeToString(execReq[1].FinalStateRootHash[:]),
PrevShnarf: utils.FmtIntHex32Bytes(2),
}
blobResp, err := blobsubmission.CraftResponse(&blobReq)
assert.NoError(t, err)
merkleRoots := aggregation.PackInMiniTrees(circuittesting.BlocksToHex(execReq[0].L2MessageHashes, execReq[1].L2MessageHashes))
req := pi_interconnection.Request{
Decompressions: []blobsubmission.Response{*blobResp},
Executions: execReq,
Aggregation: public_input.Aggregation{
FinalShnarf: blobResp.ExpectedShnarf,
ParentAggregationFinalShnarf: blobReq.PrevShnarf,
ParentStateRootHash: blobReq.ParentStateRootHash,
ParentAggregationLastBlockTimestamp: 5,
FinalTimestamp: uint(execReq[1].FinalBlockTimestamp),
LastFinalizedBlockNumber: 4,
FinalBlockNumber: uint(execReq[1].FinalBlockNumber),
LastFinalizedL1RollingHash: utils.FmtIntHex32Bytes(13),
L1RollingHash: utils.HexEncodeToString(execReq[1].LastRollingHashUpdate[:]),
LastFinalizedL1RollingHashMessageNumber: 7,
L1RollingHashMessageNumber: uint(execReq[1].LastRollingHashUpdateNumber),
L2MsgRootHashes: merkleRoots,
L2MsgMerkleTreeDepth: 5,
},
}
testPI(t, req, withSlack(0, 2))
}
func TestTwoTwoBatchBlobs(t *testing.T) {
blobs := blobtesting.ConsecutiveBlobs(t, 2, 2)
execReq := []public_input.Execution{{
L2MessageHashes: [][32]byte{internal.Uint64To32Bytes(3)},
InitialBlockTimestamp: 6,
FinalStateRootHash: internal.Uint64To32Bytes(4),
FinalBlockNumber: 5,
FinalBlockTimestamp: 6,
LastRollingHashUpdate: internal.Uint64To32Bytes(7),
LastRollingHashUpdateNumber: 8,
InitialStateRootHash: internal.Uint64To32Bytes(1),
InitialBlockNumber: 5,
FirstRollingHashUpdateNumber: 8,
}, {
L2MessageHashes: [][32]byte{internal.Uint64To32Bytes(9)},
InitialBlockTimestamp: 7,
InitialStateRootHash: internal.Uint64To32Bytes(4),
InitialBlockNumber: 6,
FirstRollingHashUpdateNumber: 9,
FinalStateRootHash: internal.Uint64To32Bytes(10),
FinalBlockNumber: 11,
FinalBlockTimestamp: 12,
LastRollingHashUpdate: internal.Uint64To32Bytes(13),
LastRollingHashUpdateNumber: 14,
}, {
L2MessageHashes: [][32]byte{internal.Uint64To32Bytes(15)},
InitialBlockTimestamp: 13,
InitialBlockNumber: 12,
InitialStateRootHash: internal.Uint64To32Bytes(10),
FirstRollingHashUpdateNumber: 15,
FinalStateRootHash: internal.Uint64To32Bytes(16),
FinalBlockNumber: 17,
FinalBlockTimestamp: 18,
LastRollingHashUpdate: internal.Uint64To32Bytes(19),
LastRollingHashUpdateNumber: 20,
}, {
InitialBlockNumber: 18,
InitialStateRootHash: internal.Uint64To32Bytes(16),
L2MessageHashes: [][32]byte{internal.Uint64To32Bytes(21)},
InitialBlockTimestamp: 19,
FirstRollingHashUpdateNumber: 21,
FinalStateRootHash: internal.Uint64To32Bytes(22),
FinalBlockNumber: 23,
FinalBlockTimestamp: 24,
LastRollingHashUpdate: internal.Uint64To32Bytes(25),
LastRollingHashUpdateNumber: 26,
}}
blobReq0 := blobsubmission.Request{
Eip4844Enabled: true,
CompressedData: base64.StdEncoding.EncodeToString(blobs[0]),
ParentStateRootHash: utils.FmtIntHex32Bytes(1),
FinalStateRootHash: utils.HexEncodeToString(execReq[1].FinalStateRootHash[:]),
PrevShnarf: utils.FmtIntHex32Bytes(2),
}
blobResp0, err := blobsubmission.CraftResponse(&blobReq0)
require.NoError(t, err)
blobReq1 := blobsubmission.Request{
Eip4844Enabled: true,
CompressedData: base64.StdEncoding.EncodeToString(blobs[1]),
ParentStateRootHash: blobReq0.FinalStateRootHash,
FinalStateRootHash: utils.HexEncodeToString(execReq[3].FinalStateRootHash[:]),
PrevShnarf: blobResp0.ExpectedShnarf,
}
blobResp1, err := blobsubmission.CraftResponse(&blobReq1)
require.NoError(t, err)
merkleRoots := aggregation.PackInMiniTrees(circuittesting.BlocksToHex(execReq[0].L2MessageHashes, execReq[1].L2MessageHashes, execReq[2].L2MessageHashes, execReq[3].L2MessageHashes))
req := pi_interconnection.Request{
Decompressions: []blobsubmission.Response{*blobResp0, *blobResp1},
Executions: execReq,
Aggregation: public_input.Aggregation{
FinalShnarf: blobResp1.ExpectedShnarf,
ParentAggregationFinalShnarf: blobReq0.PrevShnarf,
ParentStateRootHash: blobReq0.ParentStateRootHash,
ParentAggregationLastBlockTimestamp: 5,
FinalTimestamp: uint(execReq[3].FinalBlockTimestamp),
LastFinalizedBlockNumber: 4,
FinalBlockNumber: uint(execReq[3].FinalBlockNumber),
LastFinalizedL1RollingHash: utils.FmtIntHex32Bytes(7),
L1RollingHash: utils.HexEncodeToString(execReq[3].LastRollingHashUpdate[:]),
LastFinalizedL1RollingHashMessageNumber: 7,
L1RollingHashMessageNumber: uint(execReq[3].LastRollingHashUpdateNumber),
L2MsgRootHashes: merkleRoots,
L2MsgMerkleTreeDepth: 5,
},
}
testPI(t, req, withSlack(0, 2))
}
type testPIConfig struct {
slack []int
}
type testPIOption func(*testPIConfig)
func withSlack(slack ...int) testPIOption {
return func(cfg *testPIConfig) {
cfg.slack = append(cfg.slack, slack...)
}
}
func testPI(t *testing.T, req pi_interconnection.Request, options ...testPIOption) {
var cfg testPIConfig
for _, o := range options {
o(&cfg)
}
slices.Sort(cfg.slack)
cfg.slack = slices.Compact(cfg.slack)
if len(cfg.slack) == 0 {
cfg.slack = []int{0}
}
slackIterationNum := len(cfg.slack) * len(cfg.slack)
slackIterationNum *= slackIterationNum
var slack [4]int
for i := 0; i < slackIterationNum; i++ {
decomposeLittleEndian(t, slack[:], i, len(cfg.slack))
for j := range slack {
slack[j] = cfg.slack[slack[j]]
}
cfg := config.PublicInput{
MaxNbDecompression: len(req.Decompressions) + slack[0],
MaxNbExecution: len(req.Executions) + slack[1],
ExecutionMaxNbMsg: 1 + slack[2],
L2MsgMerkleDepth: 5,
L2MsgMaxNbMerkle: 1 + slack[3],
MockKeccakWizard: true,
}
t.Run(fmt.Sprintf("slack profile %v", slack), func(t *testing.T) {
compiled, err := pi_interconnection.Compile(cfg, dummy.Compile)
assert.NoError(t, err)
a, err := compiled.Assign(req)
assert.NoError(t, err)
assert.NoError(t, test.IsSolved(compiled.Circuit, &a, ecc.BLS12_377.ScalarField()))
})
}
}
func decomposeLittleEndian(t *testing.T, digits []int, n, base int) {
for i := range digits {
digits[i] = n % base
n /= base
}
assert.Zero(t, n)
}