mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete * 2.1.0 main node rollup
740 lines
31 KiB
Go
740 lines
31 KiB
Go
package compute_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/compute"
|
|
"source.quilibrium.com/quilibrium/monorepo/protobufs"
|
|
)
|
|
|
|
// FuzzComputeDeploySerialization tests ComputeDeploy serialization
|
|
func FuzzComputeDeploySerialization(f *testing.F) {
|
|
// Add seed corpus
|
|
f.Add(make([]byte, 57), make([]byte, 57), make([]byte, 585), []byte(`BASE <https://types.quilibrium.com/schema-repository/>
|
|
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
|
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
PREFIX qcl: <https://types.quilibrium.com/qcl/>
|
|
PREFIX req: <https://types.quilibrium.com/schema-repository/example/a/>
|
|
|
|
req:Request a rdfs:Class.
|
|
req:A a rdfs:Property;
|
|
rdfs:domain qcl:Uint;
|
|
qcl:size 1;
|
|
qcl:order 0;
|
|
rdfs:range req:Request.
|
|
`))
|
|
f.Add([]byte{}, []byte{}, []byte{}, []byte{})
|
|
f.Add(make([]byte, 100), make([]byte, 100), make([]byte, 100), []byte("bananaphone"))
|
|
f.Add(make([]byte, 57), make([]byte, 57), make([]byte, 585), bytes.Repeat([]byte("code"), 100))
|
|
|
|
f.Fuzz(func(t *testing.T, readPubKey, writePubKey, ownerPubKey, rdfSchema []byte) {
|
|
// Limit sizes to avoid memory issues
|
|
if len(rdfSchema) > 100000 {
|
|
return
|
|
}
|
|
|
|
// Create deploy arguments with fuzz data
|
|
deploy := &compute.ComputeDeploy{
|
|
Config: &compute.ComputeIntrinsicConfiguration{
|
|
ReadPublicKey: readPubKey,
|
|
WritePublicKey: writePubKey,
|
|
OwnerPublicKey: ownerPubKey,
|
|
},
|
|
RDFSchema: rdfSchema,
|
|
}
|
|
|
|
// Serialize
|
|
data, err := deploy.DeployToBytes()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Deserialize
|
|
deploy2, err := compute.DeployFromBytes(data)
|
|
|
|
// If deserialization succeeds, verify round-trip
|
|
if err == nil && deploy2 != nil {
|
|
if len(deploy.Config.ReadPublicKey) != 0 || len(deploy2.Config.ReadPublicKey) != 0 {
|
|
require.Equal(t, deploy.Config.ReadPublicKey, deploy2.Config.ReadPublicKey)
|
|
}
|
|
if len(deploy.Config.WritePublicKey) != 0 || len(deploy2.Config.WritePublicKey) != 0 {
|
|
require.Equal(t, deploy.Config.WritePublicKey, deploy2.Config.WritePublicKey)
|
|
}
|
|
if len(deploy.Config.OwnerPublicKey) != 0 || len(deploy2.Config.OwnerPublicKey) != 0 {
|
|
require.Equal(t, deploy.Config.OwnerPublicKey, deploy2.Config.OwnerPublicKey)
|
|
}
|
|
if len(deploy.RDFSchema) != 0 || len(deploy2.RDFSchema) != 0 {
|
|
require.Equal(t, deploy.RDFSchema, deploy2.RDFSchema)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzCodeDeploymentSerialization tests CodeDeployment serialization
|
|
func FuzzCodeDeploymentSerialization(f *testing.F) {
|
|
// Add seed corpus
|
|
// simple 32-byte width xor circuit:
|
|
xor, _ := hex.DecodeString("63726300000001030000014300000002000000010000000464617461000000075b5d75696e74380000002000000000000000056f74686572000000075b5d75696e743800000020000000000000001225726574307b312c317d736c696365323536000000075b5d75696e74380000010000000000040000000000000040000000000000000020000000430000000001000000210000004400000000020000002200000045000000000300000023000000460000000004000000240000004700000000050000002500000048000000000600000026000000490000000007000000270000004a0000000008000000280000004b0000000009000000290000004c000000000a0000002a0000004d000000000b0000002b0000004e000000000c0000002c0000004f000000000d0000002d00000050000000000e0000002e00000051000000000f0000002f00000052000000001000000030000000530000000011000000310000005400000000120000003200000055000000001300000033000000560000000014000000340000005700000000150000003500000058000000001600000036000000590000000017000000370000005a0000000018000000380000005b0000000019000000390000005c000000001a0000003a0000005d000000001b0000003b0000005e000000001c0000003c0000005f000000001d0000003d00000060000000001e0000003e00000061000000001f0000003f000000620200000000000000400000004103000000000000004000000042000000004100000041000000630000000041000000410000006400000000410000004100000065000000004100000041000000660000000041000000410000006700000000410000004100000068000000004100000041000000690000000041000000410000006a0000000041000000410000006b0000000041000000410000006c0000000041000000410000006d0000000041000000410000006e0000000041000000410000006f000000004100000041000000700000000041000000410000007100000000410000004100000072000000004100000041000000730000000041000000410000007400000000410000004100000075000000004100000041000000760000000041000000410000007700000000410000004100000078000000004100000041000000790000000041000000410000007a0000000041000000410000007b0000000041000000410000007c0000000041000000410000007d0000000041000000410000007e0000000041000000410000007f000000004100000041000000800000000041000000410000008100000000410000004100000082000000004100000041000000830000000041000000410000008400000000410000004100000085000000004100000041000000860000000041000000410000008700000000410000004100000088000000004100000041000000890000000041000000410000008a0000000041000000410000008b0000000041000000410000008c0000000041000000410000008d0000000041000000410000008e0000000041000000410000008f000000004100000041000000900000000041000000410000009100000000410000004100000092000000004100000041000000930000000041000000410000009400000000410000004100000095000000004100000041000000960000000041000000410000009700000000410000004100000098000000004100000041000000990000000041000000410000009a0000000041000000410000009b0000000041000000410000009c0000000041000000410000009d0000000041000000410000009e0000000041000000410000009f000000004100000041000000a0000000004100000041000000a1000000004100000041000000a2000000004100000041000000a3000000004100000041000000a4000000004100000041000000a5000000004100000041000000a6000000004100000041000000a7000000004100000041000000a8000000004100000041000000a9000000004100000041000000aa000000004100000041000000ab000000004100000041000000ac000000004100000041000000ad000000004100000041000000ae000000004100000041000000af000000004100000041000000b0000000004100000041000000b1000000004100000041000000b2000000004100000041000000b3000000004100000041000000b4000000004100000041000000b5000000004100000041000000b6000000004100000041000000b7000000004100000041000000b8000000004100000041000000b9000000004100000041000000ba000000004100000041000000bb000000004100000041000000bc000000004100000041000000bd000000004100000041000000be000000004100000041000000bf000000004100000041000000c0000000004100000041000000c1000000004100000041000000c2000000004100000041000000c3000000004100000041000000c4000000004100000041000000c5000000004100000041000000c6000000004100000041000000c7000000004100000041000000c8000000004100000041000000c9000000004100000041000000ca000000004100000041000000cb000000004100000041000000cc000000004100000041000000cd000000004100000041000000ce000000004100000041000000cf000000004100000041000000d0000000004100000041000000d1000000004100000041000000d2000000004100000041000000d3000000004100000041000000d4000000004100000041000000d5000000004100000041000000d6000000004100000041000000d7000000004100000041000000d8000000004100000041000000d9000000004100000041000000da000000004100000041000000db000000004100000041000000dc000000004100000041000000dd000000004100000041000000de000000004100000041000000df000000004100000041000000e0000000004100000041000000e1000000004100000041000000e2000000004100000041000000e3000000004100000041000000e4000000004100000041000000e5000000004100000041000000e6000000004100000041000000e7000000004100000041000000e8000000004100000041000000e9000000004100000041000000ea000000004100000041000000eb000000004100000041000000ec000000004100000041000000ed000000004100000041000000ee000000004100000041000000ef000000004100000041000000f0000000004100000041000000f1000000004100000041000000f2000000004100000041000000f3000000004100000041000000f4000000004100000041000000f5000000004100000041000000f6000000004100000041000000f7000000004100000041000000f8000000004100000041000000f9000000004100000041000000fa000000004100000041000000fb000000004100000041000000fc000000004100000041000000fd000000004100000041000000fe000000004100000041000000ff000000004100000041000001000000000041000000410000010100000000410000004100000102000000004100000041000001030000000041000000410000010400000000410000004100000105000000004100000041000001060000000041000000410000010700000000410000004100000108000000004100000041000001090000000041000000410000010a0000000041000000410000010b0000000041000000410000010c0000000041000000410000010d0000000041000000410000010e0000000041000000410000010f000000004100000041000001100000000041000000410000011100000000410000004100000112000000004100000041000001130000000041000000410000011400000000410000004100000115000000004100000041000001160000000041000000410000011700000000410000004100000118000000004100000041000001190000000041000000410000011a0000000041000000410000011b0000000041000000410000011c0000000041000000410000011d0000000041000000410000011e0000000041000000410000011f000000004100000041000001200000000041000000410000012100000000410000004100000122000000004100000041000001230000000041000000410000012400000000410000004100000125000000004100000041000001260000000041000000410000012700000000410000004100000128000000004100000041000001290000000041000000410000012a0000000041000000410000012b0000000041000000410000012c0000000041000000410000012d0000000041000000410000012e0000000041000000410000012f000000004100000041000001300000000041000000410000013100000000410000004100000132000000004100000041000001330000000041000000410000013400000000410000004100000135000000004100000041000001360000000041000000410000013700000000410000004100000138000000004100000041000001390000000041000000410000013a0000000041000000410000013b0000000041000000410000013c0000000041000000410000013d0000000041000000410000013e0000000041000000410000013f000000004100000041000001400000000041000000410000014100000000410000004100000142")
|
|
f.Add(make([]byte, 32), xor, "qcl:ByteArray;qcl:ByteArray", "qcl:ByteArray")
|
|
f.Add(make([]byte, 32), []byte{}, "waffleiron", "waffleiron")
|
|
f.Add(bytes.Repeat([]byte{0xaa}, 32), bytes.Repeat([]byte("aa"), 500), "", "")
|
|
|
|
f.Fuzz(func(t *testing.T, domain, circuit []byte, inputTypes string, outputTypes string) {
|
|
if len(domain) != 32 {
|
|
return
|
|
}
|
|
if len(circuit) > 100000 { // Limit code size
|
|
return
|
|
}
|
|
|
|
// Create code deployment with fuzz data
|
|
deployment := &compute.CodeDeployment{}
|
|
copy(deployment.Domain[:], domain)
|
|
deployment.Circuit = circuit
|
|
// Handle InputTypes split
|
|
inputParts := strings.Split(inputTypes, ";")
|
|
if len(inputParts) >= 2 {
|
|
deployment.InputTypes[0] = inputParts[0]
|
|
deployment.InputTypes[1] = inputParts[1]
|
|
} else if len(inputParts) == 1 {
|
|
deployment.InputTypes[0] = inputParts[0]
|
|
deployment.InputTypes[1] = ""
|
|
}
|
|
|
|
deployment.OutputTypes = strings.Split(outputTypes, ";")
|
|
|
|
// Serialize
|
|
data, err := deployment.ToBytes()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Deserialize
|
|
deployment2 := &compute.CodeDeployment{}
|
|
err = deployment2.FromBytes(data, nil)
|
|
|
|
// If deserialization succeeds, verify round-trip
|
|
if err == nil {
|
|
require.Equal(t, deployment.Domain, deployment2.Domain)
|
|
// Handle nil vs empty slice for Circuit
|
|
if len(deployment.Circuit) == 0 && len(deployment2.Circuit) == 0 {
|
|
// Both empty, OK
|
|
} else {
|
|
require.Equal(t, deployment.Circuit, deployment2.Circuit)
|
|
}
|
|
require.Equal(t, deployment.InputTypes, deployment2.InputTypes)
|
|
require.Equal(t, deployment.OutputTypes, deployment2.OutputTypes)
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzCodeExecuteSerialization tests CodeExecute serialization
|
|
func FuzzCodeExecuteSerialization(f *testing.F) {
|
|
// Add seed corpus
|
|
f.Add(make([]byte, 32), make([]byte, 32), make([]byte, 100), make([]byte, 100))
|
|
f.Add(make([]byte, 32), make([]byte, 32), []byte{}, []byte{})
|
|
f.Add(bytes.Repeat([]byte{0x55}, 32), bytes.Repeat([]byte{0xaa}, 32), make([]byte, 200), make([]byte, 200))
|
|
|
|
f.Fuzz(func(t *testing.T, domain, rendezvous, pop0, pop1 []byte) {
|
|
if len(domain) != 32 || len(rendezvous) != 32 {
|
|
return
|
|
}
|
|
if len(pop0) > 100000 || len(pop1) > 100000 { // Limit sizes
|
|
return
|
|
}
|
|
|
|
// Create code execute with fuzz data
|
|
execute := &compute.CodeExecute{}
|
|
copy(execute.Domain[:], domain)
|
|
copy(execute.Rendezvous[:], rendezvous)
|
|
execute.ProofOfPayment = [2][]byte{pop0, pop1}
|
|
execute.ExecuteOperations = []*compute.ExecuteOperation{}
|
|
|
|
// Serialize
|
|
data, err := execute.ToBytes()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Deserialize
|
|
execute2 := &compute.CodeExecute{}
|
|
err = execute2.FromBytes(data, nil, nil, nil, nil, nil, nil, nil)
|
|
|
|
// If deserialization succeeds, verify round-trip
|
|
if err == nil {
|
|
require.Equal(t, execute.Domain, execute2.Domain)
|
|
require.Equal(t, execute.Rendezvous, execute2.Rendezvous)
|
|
require.Equal(t, execute.ProofOfPayment, execute2.ProofOfPayment)
|
|
require.Equal(t, len(execute.ExecuteOperations), len(execute2.ExecuteOperations))
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzComputeOperationTypeDetection tests operation type detection
|
|
func FuzzComputeOperationTypeDetection(f *testing.F) {
|
|
// Add various type prefixes
|
|
f.Add(uint32(protobufs.ComputeDeploymentType), []byte{})
|
|
f.Add(uint32(protobufs.CodeDeploymentType), []byte{})
|
|
f.Add(uint32(protobufs.CodeExecuteType), []byte{})
|
|
f.Add(uint32(999999), []byte{}) // Invalid type
|
|
f.Add(uint32(0), make([]byte, 100))
|
|
f.Add(uint32(^uint32(0)), make([]byte, 50))
|
|
|
|
f.Fuzz(func(t *testing.T, typePrefix uint32, additionalData []byte) {
|
|
// Create data with type prefix
|
|
buf := new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, typePrefix)
|
|
buf.Write(additionalData)
|
|
data := buf.Bytes()
|
|
|
|
// Try deserializing based on type
|
|
switch typePrefix {
|
|
case protobufs.ComputeDeploymentType:
|
|
_, _ = compute.DeployFromBytes(data)
|
|
case protobufs.CodeDeploymentType:
|
|
obj := &compute.CodeDeployment{}
|
|
_ = obj.FromBytes(data, nil)
|
|
case protobufs.CodeExecuteType:
|
|
obj := &compute.CodeExecute{}
|
|
_ = obj.FromBytes(data, nil, nil, nil, nil, nil, nil, nil)
|
|
}
|
|
|
|
// Test that wrong types fail appropriately
|
|
if typePrefix != protobufs.CodeDeploymentType && len(data) >= 4 {
|
|
obj := &compute.CodeDeployment{}
|
|
err := obj.FromBytes(data, nil)
|
|
if typePrefix >= protobufs.ComputeDeploymentType && typePrefix <= protobufs.CodeExecuteType && typePrefix != protobufs.CodeFinalizeType {
|
|
// Should fail for wrong but valid type
|
|
require.Error(t, err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzDeserializationRobustness tests deserialization with completely random data
|
|
func FuzzDeserializationRobustness(f *testing.F) {
|
|
// Add various malformed inputs
|
|
f.Add([]byte{})
|
|
f.Add([]byte{0x00})
|
|
f.Add([]byte{0x00, 0x00, 0x00, 0x01}) // Just type prefix
|
|
f.Add([]byte{0xff, 0xff, 0xff, 0xff}) // Invalid type
|
|
f.Add(bytes.Repeat([]byte{0x00}, 1000))
|
|
f.Add(bytes.Repeat([]byte{0xff}, 1000))
|
|
|
|
// Add some structured but potentially malformed data
|
|
for i := uint32(1); i <= 3; i++ {
|
|
buf := new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, i)
|
|
buf.Write(bytes.Repeat([]byte{0x41}, 100))
|
|
f.Add(buf.Bytes())
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
// Test all deserialization functions with random data
|
|
// They should either succeed or fail gracefully without panicking
|
|
|
|
// Test deploy
|
|
_, _ = compute.DeployFromBytes(data)
|
|
|
|
// Test code deployment
|
|
deployment := &compute.CodeDeployment{}
|
|
_ = deployment.FromBytes(data, nil)
|
|
|
|
// Test code execute
|
|
execute := &compute.CodeExecute{}
|
|
_ = execute.FromBytes(data, nil, nil, nil, nil, nil, nil, nil)
|
|
})
|
|
}
|
|
|
|
// FuzzLengthOverflows tests handling of length field overflows
|
|
func FuzzLengthOverflows(f *testing.F) {
|
|
// Add cases with large length values
|
|
f.Add(uint32(0xFFFFFFFF), uint32(0xFFFFFFFF), uint32(0xFFFFFFFF))
|
|
f.Add(uint32(1<<31), uint32(1<<31), uint32(1<<31))
|
|
f.Add(uint32(1000000), uint32(1000000), uint32(1000000))
|
|
f.Add(uint32(1), uint32(2), uint32(3))
|
|
|
|
f.Fuzz(func(t *testing.T, codeLen, invocationLen, contextLen uint32) {
|
|
// Create CodeExecute with potentially overflowing lengths
|
|
buf := new(bytes.Buffer)
|
|
|
|
// Write type prefix
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeExecuteType))
|
|
|
|
// Write domain
|
|
buf.Write(make([]byte, 32))
|
|
|
|
// Write rendezvous
|
|
buf.Write(make([]byte, 32))
|
|
|
|
// Write ProofOfPayment[0] with large length
|
|
binary.Write(buf, binary.BigEndian, invocationLen)
|
|
// Don't actually write that much data
|
|
buf.Write(make([]byte, min(int(invocationLen), 100)))
|
|
|
|
// Write ProofOfPayment[1] with large length
|
|
binary.Write(buf, binary.BigEndian, contextLen)
|
|
buf.Write(make([]byte, min(int(contextLen), 100)))
|
|
|
|
// Write ExecuteOperations count
|
|
binary.Write(buf, binary.BigEndian, uint32(0))
|
|
|
|
// Try to deserialize - should handle gracefully
|
|
execute := &compute.CodeExecute{}
|
|
_ = execute.FromBytes(buf.Bytes(), nil, nil, nil, nil, nil, nil, nil)
|
|
})
|
|
}
|
|
|
|
// FuzzCodeDataValidation tests various code data patterns
|
|
func FuzzCodeDataValidation(f *testing.F) {
|
|
// Add various code patterns
|
|
f.Add([]byte("function() {}"), []byte("{}"))
|
|
f.Add([]byte(""), []byte(""))
|
|
f.Add([]byte("\x00\x00\x00\x00"), []byte("\xff\xff\xff\xff"))
|
|
f.Add([]byte("import os; os.system('bad')"), []byte("{}"))
|
|
f.Add(bytes.Repeat([]byte("A"), 1000), []byte("null"))
|
|
|
|
f.Fuzz(func(t *testing.T, code, context []byte) {
|
|
if len(code) > 100000 || len(context) > 100000 {
|
|
return
|
|
}
|
|
|
|
// Test with CodeDeployment
|
|
deployment := &compute.CodeDeployment{
|
|
Circuit: code,
|
|
InputTypes: [2]string{"test", "test"},
|
|
OutputTypes: []string{"test"},
|
|
}
|
|
copy(deployment.Domain[:], make([]byte, 32))
|
|
|
|
data, err := deployment.ToBytes()
|
|
if err == nil {
|
|
deployment2 := &compute.CodeDeployment{}
|
|
err2 := deployment2.FromBytes(data, nil)
|
|
if err2 == nil {
|
|
// Handle nil vs empty slice for Circuit
|
|
if len(deployment.Circuit) == 0 && len(deployment2.Circuit) == 0 {
|
|
// Both empty, OK
|
|
} else {
|
|
require.Equal(t, deployment.Circuit, deployment2.Circuit)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test with CodeExecute
|
|
execute := &compute.CodeExecute{
|
|
ProofOfPayment: [2][]byte{code, context},
|
|
ExecuteOperations: []*compute.ExecuteOperation{},
|
|
}
|
|
copy(execute.Domain[:], make([]byte, 32))
|
|
copy(execute.Rendezvous[:], make([]byte, 32))
|
|
|
|
data, err = execute.ToBytes()
|
|
if err == nil {
|
|
execute2 := &compute.CodeExecute{}
|
|
err2 := execute2.FromBytes(data, nil, nil, nil, nil, nil, nil, nil)
|
|
if err2 == nil {
|
|
require.Equal(t, execute.ProofOfPayment[0], execute2.ProofOfPayment[0])
|
|
require.Equal(t, execute.ProofOfPayment[1], execute2.ProofOfPayment[1])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzNilFieldHandling tests handling of nil/empty fields
|
|
func FuzzNilFieldHandling(f *testing.F) {
|
|
// Add cases with various nil/empty combinations
|
|
f.Add(true, true, true, true)
|
|
f.Add(true, true, true, false)
|
|
f.Add(true, true, false, true)
|
|
f.Add(true, true, false, false)
|
|
f.Add(true, false, true, true)
|
|
f.Add(true, false, true, false)
|
|
f.Add(true, false, false, true)
|
|
f.Add(true, false, false, false)
|
|
f.Add(false, true, true, true)
|
|
f.Add(false, true, true, false)
|
|
f.Add(false, true, false, true)
|
|
f.Add(false, true, false, false)
|
|
f.Add(false, false, true, true)
|
|
f.Add(false, false, true, false)
|
|
f.Add(false, false, false, true)
|
|
f.Add(false, false, false, false)
|
|
|
|
f.Fuzz(func(t *testing.T, hasReadKey, hasWriteKey, hasOwnerKey, hasSchema bool) {
|
|
deploy := &compute.ComputeDeploy{
|
|
Config: &compute.ComputeIntrinsicConfiguration{},
|
|
}
|
|
|
|
if hasReadKey {
|
|
deploy.Config.ReadPublicKey = make([]byte, 57)
|
|
}
|
|
if hasWriteKey {
|
|
deploy.Config.WritePublicKey = make([]byte, 57)
|
|
}
|
|
if hasOwnerKey {
|
|
deploy.Config.OwnerPublicKey = make([]byte, 585)
|
|
}
|
|
if hasSchema {
|
|
deploy.RDFSchema = []byte("test schema")
|
|
} else {
|
|
// RDFSchema is required to be non-empty
|
|
deploy.RDFSchema = []byte("x")
|
|
}
|
|
|
|
// Serialize
|
|
data, err := deploy.DeployToBytes()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Deserialize
|
|
deploy2, err := compute.DeployFromBytes(data)
|
|
if err == nil && deploy2 != nil {
|
|
if hasReadKey {
|
|
require.Equal(t, deploy.Config.ReadPublicKey, deploy2.Config.ReadPublicKey)
|
|
}
|
|
if hasWriteKey {
|
|
require.Equal(t, deploy.Config.WritePublicKey, deploy2.Config.WritePublicKey)
|
|
}
|
|
if hasOwnerKey {
|
|
require.Equal(t, deploy.Config.OwnerPublicKey, deploy2.Config.OwnerPublicKey)
|
|
}
|
|
require.Equal(t, deploy.RDFSchema, deploy2.RDFSchema)
|
|
}
|
|
})
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
// FuzzComputeDeployDeserialization specifically tests DeployFromBytes robustness
|
|
func FuzzComputeDeployDeserialization(f *testing.F) {
|
|
// Add valid cases
|
|
validDeploy := &compute.ComputeDeploy{
|
|
Config: &compute.ComputeIntrinsicConfiguration{
|
|
ReadPublicKey: make([]byte, 57),
|
|
WritePublicKey: make([]byte, 57),
|
|
OwnerPublicKey: make([]byte, 585),
|
|
},
|
|
RDFSchema: []byte("test schema"),
|
|
}
|
|
validData, _ := validDeploy.DeployToBytes()
|
|
f.Add(validData)
|
|
|
|
// Add truncated valid data at various points
|
|
for i := 0; i < len(validData) && i < 20; i++ {
|
|
f.Add(validData[:i])
|
|
}
|
|
|
|
// Add malformed type prefix cases
|
|
buf := new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(99999)) // Invalid type
|
|
buf.Write(make([]byte, 100))
|
|
f.Add(buf.Bytes())
|
|
|
|
// Add cases with invalid lengths
|
|
buf = new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.ComputeDeploymentType))
|
|
binary.Write(buf, binary.BigEndian, uint32(0xFFFFFFFF)) // Huge length for read key
|
|
f.Add(buf.Bytes())
|
|
|
|
// Add empty schema case
|
|
buf = new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.ComputeDeploymentType))
|
|
binary.Write(buf, binary.BigEndian, uint32(57))
|
|
buf.Write(make([]byte, 57))
|
|
binary.Write(buf, binary.BigEndian, uint32(57))
|
|
buf.Write(make([]byte, 57))
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty schema
|
|
f.Add(buf.Bytes())
|
|
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
result, err := compute.DeployFromBytes(data)
|
|
|
|
// If it succeeds, verify the result is valid
|
|
if err == nil && result != nil {
|
|
// Verify keys are either nil/empty or 57 bytes
|
|
if len(result.Config.ReadPublicKey) > 0 {
|
|
require.Equal(t, 57, len(result.Config.ReadPublicKey))
|
|
}
|
|
if len(result.Config.WritePublicKey) > 0 {
|
|
require.Equal(t, 57, len(result.Config.WritePublicKey))
|
|
}
|
|
if len(result.Config.OwnerPublicKey) > 0 {
|
|
require.Equal(t, 585, len(result.Config.OwnerPublicKey))
|
|
}
|
|
// Schema must not be empty
|
|
require.NotEmpty(t, result.RDFSchema)
|
|
|
|
// Verify round-trip works
|
|
data2, err2 := result.DeployToBytes()
|
|
require.NoError(t, err2)
|
|
result2, err3 := compute.DeployFromBytes(data2)
|
|
require.NoError(t, err3)
|
|
require.Equal(t, result.Config.ReadPublicKey, result2.Config.ReadPublicKey)
|
|
require.Equal(t, result.Config.WritePublicKey, result2.Config.WritePublicKey)
|
|
require.Equal(t, result.Config.OwnerPublicKey, result2.Config.OwnerPublicKey)
|
|
require.Equal(t, result.RDFSchema, result2.RDFSchema)
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzCodeDeploymentDeserialization specifically tests CodeDeployment.FromBytes robustness
|
|
func FuzzCodeDeploymentDeserialization(f *testing.F) {
|
|
// Add valid case
|
|
validDeployment := &compute.CodeDeployment{
|
|
Circuit: []byte("test circuit"),
|
|
InputTypes: [2]string{"type1", "type2"},
|
|
OutputTypes: []string{"output1", "output2"},
|
|
}
|
|
copy(validDeployment.Domain[:], make([]byte, 32))
|
|
validData, _ := validDeployment.ToBytes()
|
|
f.Add(validData)
|
|
|
|
// Add truncated valid data
|
|
for i := 0; i < len(validData) && i < 50; i++ {
|
|
f.Add(validData[:i])
|
|
}
|
|
|
|
// Add wrong type prefix
|
|
buf := new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeExecuteType)) // Wrong type
|
|
buf.Write(make([]byte, 100))
|
|
f.Add(buf.Bytes())
|
|
|
|
// Add cases with huge string lengths
|
|
buf = new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeDeploymentType))
|
|
buf.Write(make([]byte, 32)) // Domain
|
|
binary.Write(buf, binary.BigEndian, uint32(10)) // Circuit length
|
|
buf.Write([]byte("circuit123"))
|
|
binary.Write(buf, binary.BigEndian, uint32(0xFFFFFFFF)) // Huge InputTypes[0] length
|
|
f.Add(buf.Bytes())
|
|
|
|
// Add case with many output types
|
|
buf = new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeDeploymentType))
|
|
buf.Write(make([]byte, 32)) // Domain
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty circuit
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty InputTypes[0]
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty InputTypes[1]
|
|
binary.Write(buf, binary.BigEndian, uint32(10000)) // Many output types
|
|
f.Add(buf.Bytes())
|
|
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
deployment := &compute.CodeDeployment{}
|
|
err := deployment.FromBytes(data, nil)
|
|
|
|
// If it succeeds, verify the result is valid
|
|
if err == nil {
|
|
// Domain should be 32 bytes
|
|
require.Equal(t, 32, len(deployment.Domain))
|
|
|
|
// Verify round-trip works
|
|
data2, err2 := deployment.ToBytes()
|
|
require.NoError(t, err2)
|
|
deployment2 := &compute.CodeDeployment{}
|
|
err3 := deployment2.FromBytes(data2, nil)
|
|
require.NoError(t, err3)
|
|
require.Equal(t, deployment.Domain, deployment2.Domain)
|
|
|
|
// Handle nil vs empty slice
|
|
if len(deployment.Circuit) == 0 && len(deployment2.Circuit) == 0 {
|
|
// Both empty, OK
|
|
} else {
|
|
require.Equal(t, deployment.Circuit, deployment2.Circuit)
|
|
}
|
|
require.Equal(t, deployment.InputTypes, deployment2.InputTypes)
|
|
require.Equal(t, deployment.OutputTypes, deployment2.OutputTypes)
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzCodeExecuteDeserialization specifically tests CodeExecute.FromBytes robustness
|
|
func FuzzCodeExecuteDeserialization(f *testing.F) {
|
|
// Add valid case
|
|
validExecute := &compute.CodeExecute{
|
|
ProofOfPayment: [2][]byte{[]byte("proof1"), []byte("proof2")},
|
|
ExecuteOperations: []*compute.ExecuteOperation{
|
|
{
|
|
Application: compute.Application{
|
|
Address: []byte("app1"),
|
|
ExecutionContext: compute.ExecutionContextIntrinsic,
|
|
},
|
|
Identifier: []byte("id1"),
|
|
Dependencies: [][]byte{[]byte("dep1"), []byte("dep2")},
|
|
},
|
|
},
|
|
}
|
|
copy(validExecute.Domain[:], make([]byte, 32))
|
|
copy(validExecute.Rendezvous[:], make([]byte, 32))
|
|
validData, _ := validExecute.ToBytes()
|
|
f.Add(validData)
|
|
|
|
// Add truncated valid data
|
|
for i := 0; i < len(validData) && i < 100; i += 5 {
|
|
f.Add(validData[:i])
|
|
}
|
|
|
|
// Add wrong type prefix
|
|
buf := new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeDeploymentType)) // Wrong type
|
|
buf.Write(make([]byte, 100))
|
|
f.Add(buf.Bytes())
|
|
|
|
// Add case with huge ProofOfPayment lengths
|
|
buf = new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeExecuteType))
|
|
buf.Write(make([]byte, 32)) // Domain
|
|
buf.Write(make([]byte, 32)) // Rendezvous
|
|
binary.Write(buf, binary.BigEndian, uint32(0xFFFFFFFF)) // Huge ProofOfPayment[0]
|
|
f.Add(buf.Bytes())
|
|
|
|
// Add case with many operations
|
|
buf = new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeExecuteType))
|
|
buf.Write(make([]byte, 32)) // Domain
|
|
buf.Write(make([]byte, 32)) // Rendezvous
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty ProofOfPayment[0]
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty ProofOfPayment[1]
|
|
binary.Write(buf, binary.BigEndian, uint32(10000)) // Many operations
|
|
f.Add(buf.Bytes())
|
|
|
|
// Add case with malformed operation
|
|
buf = new(bytes.Buffer)
|
|
binary.Write(buf, binary.BigEndian, uint32(protobufs.CodeExecuteType))
|
|
buf.Write(make([]byte, 32)) // Domain
|
|
buf.Write(make([]byte, 32)) // Rendezvous
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty ProofOfPayment[0]
|
|
binary.Write(buf, binary.BigEndian, uint32(0)) // Empty ProofOfPayment[1]
|
|
binary.Write(buf, binary.BigEndian, uint32(1)) // One operation
|
|
binary.Write(buf, binary.BigEndian, uint32(0xFFFFFFFF)) // Huge address length
|
|
f.Add(buf.Bytes())
|
|
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
execute := &compute.CodeExecute{}
|
|
err := execute.FromBytes(data, nil, nil, nil, nil, nil, nil, nil)
|
|
|
|
// If it succeeds, verify the result is valid
|
|
if err == nil {
|
|
// Domain and Rendezvous should be 32 bytes
|
|
require.Equal(t, 32, len(execute.Domain))
|
|
require.Equal(t, 32, len(execute.Rendezvous))
|
|
|
|
// ProofOfPayment should have exactly 2 elements
|
|
require.Equal(t, 2, len(execute.ProofOfPayment))
|
|
|
|
// Verify operations are valid
|
|
for _, op := range execute.ExecuteOperations {
|
|
require.NotNil(t, op)
|
|
require.NotNil(t, op.Application.Address)
|
|
// ExecutionContext should be valid (0-2)
|
|
require.LessOrEqual(t, uint8(op.Application.ExecutionContext), uint8(2))
|
|
}
|
|
|
|
// Verify round-trip works
|
|
data2, err2 := execute.ToBytes()
|
|
require.NoError(t, err2)
|
|
execute2 := &compute.CodeExecute{}
|
|
err3 := execute2.FromBytes(data2, nil, nil, nil, nil, nil, nil, nil)
|
|
require.NoError(t, err3)
|
|
require.Equal(t, execute.Domain, execute2.Domain)
|
|
require.Equal(t, execute.Rendezvous, execute2.Rendezvous)
|
|
require.Equal(t, execute.ProofOfPayment, execute2.ProofOfPayment)
|
|
require.Equal(t, len(execute.ExecuteOperations), len(execute2.ExecuteOperations))
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzMixedTypeDeserialization tests deserialization with data that could be any type
|
|
func FuzzMixedTypeDeserialization(f *testing.F) {
|
|
// Add valid data for each type
|
|
deploy := &compute.ComputeDeploy{
|
|
Config: &compute.ComputeIntrinsicConfiguration{
|
|
ReadPublicKey: make([]byte, 57),
|
|
WritePublicKey: make([]byte, 57),
|
|
OwnerPublicKey: make([]byte, 585),
|
|
},
|
|
RDFSchema: []byte("schema"),
|
|
}
|
|
deployData, _ := deploy.DeployToBytes()
|
|
f.Add(deployData)
|
|
|
|
deployment := &compute.CodeDeployment{
|
|
Circuit: []byte("circuit"),
|
|
InputTypes: [2]string{"in1", "in2"},
|
|
OutputTypes: []string{"out1"},
|
|
}
|
|
copy(deployment.Domain[:], make([]byte, 32))
|
|
deploymentData, _ := deployment.ToBytes()
|
|
f.Add(deploymentData)
|
|
|
|
execute := &compute.CodeExecute{
|
|
ProofOfPayment: [2][]byte{[]byte("p1"), []byte("p2")},
|
|
ExecuteOperations: []*compute.ExecuteOperation{},
|
|
}
|
|
copy(execute.Domain[:], make([]byte, 32))
|
|
copy(execute.Rendezvous[:], make([]byte, 32))
|
|
executeData, _ := execute.ToBytes()
|
|
f.Add(executeData)
|
|
|
|
// Add random data
|
|
f.Add([]byte{})
|
|
f.Add(make([]byte, 1000))
|
|
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
// Try to determine type and deserialize appropriately
|
|
if len(data) >= 4 {
|
|
typePrefix := binary.BigEndian.Uint32(data[:4])
|
|
|
|
switch typePrefix {
|
|
case protobufs.ComputeDeploymentType:
|
|
result, err := compute.DeployFromBytes(data)
|
|
if err == nil {
|
|
// Should be able to serialize back
|
|
_, err2 := result.DeployToBytes()
|
|
require.NoError(t, err2)
|
|
}
|
|
|
|
case protobufs.CodeDeploymentType:
|
|
deployment := &compute.CodeDeployment{}
|
|
err := deployment.FromBytes(data, nil)
|
|
if err == nil {
|
|
// Should be able to serialize back
|
|
_, err2 := deployment.ToBytes()
|
|
require.NoError(t, err2)
|
|
}
|
|
|
|
case protobufs.CodeExecuteType:
|
|
execute := &compute.CodeExecute{}
|
|
err := execute.FromBytes(data, nil, nil, nil, nil, nil, nil, nil)
|
|
if err == nil {
|
|
// Should be able to serialize back
|
|
_, err2 := execute.ToBytes()
|
|
require.NoError(t, err2)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Also try deserializing as each type regardless of prefix
|
|
// This ensures invalid type prefixes are handled properly
|
|
_, _ = compute.DeployFromBytes(data)
|
|
|
|
deployment := &compute.CodeDeployment{}
|
|
_ = deployment.FromBytes(data, nil)
|
|
|
|
execute := &compute.CodeExecute{}
|
|
_ = execute.FromBytes(data, nil, nil, nil, nil, nil, nil, nil)
|
|
})
|
|
}
|