ceremonyclient/node/execution/engines/compute_execution_engine_test.go
Cassandra Heart c797d482f9
v2.1.0.5 (#457)
* wip: conversion of hotstuff from flow into Q-oriented model

* bulk of tests

* remaining non-integration tests

* add integration test, adjust log interface, small tweaks

* further adjustments, restore full pacemaker shape

* add component lifecycle management+supervisor

* further refinements

* resolve timeout hanging

* mostly finalized state for consensus

* bulk of engine swap out

* lifecycle-ify most types

* wiring nearly complete, missing needed hooks for proposals

* plugged in, vetting message validation paths

* global consensus, plugged in and verified

* app shard now wired in too

* do not decode empty keys.yml (#456)

* remove obsolete engine.maxFrames config parameter (#454)

* default to Info log level unless debug is enabled (#453)

* respect config's  "logging" section params, remove obsolete single-file logging (#452)

* Trivial code cleanup aiming to reduce Go compiler warnings (#451)

* simplify range traversal

* simplify channel read for single select case

* delete rand.Seed() deprecated in Go 1.20 and no-op as of Go 1.24

* simplify range traversal

* simplify channel read for single select case

* remove redundant type from array

* simplify range traversal

* simplify channel read for single select case

* RC slate

* finalize 2.1.0.5

* Update comments in StrictMonotonicCounter

Fix comment formatting and clarify description.

---------

Co-authored-by: Black Swan <3999712+blacks1ne@users.noreply.github.com>
2025-11-11 05:00:17 -06:00

5551 lines
186 KiB
Go

package engines_test
import (
"bytes"
"context"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"math/big"
"slices"
"strings"
"sync"
"testing"
"time"
"github.com/cloudflare/circl/sign/ed448"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"golang.org/x/crypto/sha3"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/wrapperspb"
"source.quilibrium.com/quilibrium/monorepo/config"
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
"source.quilibrium.com/quilibrium/monorepo/node/consensus/app"
"source.quilibrium.com/quilibrium/monorepo/node/consensus/global"
consensustime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
"source.quilibrium.com/quilibrium/monorepo/node/execution/engines"
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/compute"
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token"
hgstate "source.quilibrium.com/quilibrium/monorepo/node/execution/state/hypergraph"
"source.quilibrium.com/quilibrium/monorepo/node/keys"
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
pstore "source.quilibrium.com/quilibrium/monorepo/node/store"
"source.quilibrium.com/quilibrium/monorepo/node/tests"
"source.quilibrium.com/quilibrium/monorepo/protobufs"
"source.quilibrium.com/quilibrium/monorepo/types/channel"
consensustypes "source.quilibrium.com/quilibrium/monorepo/types/consensus"
"source.quilibrium.com/quilibrium/monorepo/types/crypto"
"source.quilibrium.com/quilibrium/monorepo/types/execution"
"source.quilibrium.com/quilibrium/monorepo/types/hypergraph"
tkeys "source.quilibrium.com/quilibrium/monorepo/types/keys"
"source.quilibrium.com/quilibrium/monorepo/types/mocks"
tp2p "source.quilibrium.com/quilibrium/monorepo/types/p2p"
"source.quilibrium.com/quilibrium/monorepo/types/schema"
"source.quilibrium.com/quilibrium/monorepo/types/store"
"source.quilibrium.com/quilibrium/monorepo/types/tries"
)
type mockEncryptedChannel struct{}
// DecryptTwoPartyMessage implements channel.EncryptedChannel.
func (m *mockEncryptedChannel) DecryptTwoPartyMessage(ratchetState string, envelope *channel.P2PChannelEnvelope) (newRatchetState string, message []byte, err error) {
panic("unimplemented")
}
// EncryptTwoPartyMessage implements channel.EncryptedChannel.
func (m *mockEncryptedChannel) EncryptTwoPartyMessage(ratchetState string, message []byte) (newRatchetState string, envelope *channel.P2PChannelEnvelope, err error) {
panic("unimplemented")
}
// EstablishTwoPartyChannel implements channel.EncryptedChannel.
func (m *mockEncryptedChannel) EstablishTwoPartyChannel(isSender bool, sendingIdentityPrivateKey []byte, sendingSignedPrePrivateKey []byte, receivingIdentityKey []byte, receivingSignedPreKey []byte) (string, error) {
panic("unimplemented")
}
// makeExtrinsicAddress creates a 32-byte address for ExecutionContextExtrinsic testing
func makeExtrinsicAddress(name string) []byte {
addr := make([]byte, 32)
copy(addr, []byte(name))
return addr
}
func generateRDFPrelude(
appAddress []byte,
config *token.TokenIntrinsicConfiguration,
) string {
appAddressHex := hex.EncodeToString(appAddress)
prelude := "BASE <https://types.quilibrium.com/schema-repository/>\n" +
"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n" +
"PREFIX qcl: <https://types.quilibrium.com/qcl/>\n" +
"PREFIX coin: <https://types.quilibrium.com/schema-repository/token/" + appAddressHex + "/coin/>\n"
if config.Behavior&token.Acceptable != 0 {
prelude += "PREFIX pending: <https://types.quilibrium.com/schema-repository/token/" + appAddressHex + "/pending/>\n"
}
prelude += "\n"
return prelude
}
func prepareRDFSchemaFromConfig(
appAddress []byte,
config *token.TokenIntrinsicConfiguration,
) (string, error) {
schema := generateRDFPrelude(appAddress, config)
schema += "coin:Coin a rdfs:Class.\n" +
"coin:FrameNumber a rdfs:Property;\n" +
" rdfs:domain qcl:Uint;\n" +
" qcl:size 8;\n" +
" qcl:order 0;\n" +
" rdfs:range coin:Coin.\n" +
"coin:Commitment a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 1;\n" +
" rdfs:range coin:Coin.\n" +
"coin:OneTimeKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 2;\n" +
" rdfs:range coin:Coin.\n" +
"coin:VerificationKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 3;\n" +
" rdfs:range coin:Coin.\n" +
"coin:CoinBalance a rdfs:Property;\n" +
" rdfs:domain qcl:Uint;\n" +
" qcl:size 56;\n" +
" qcl:order 4;\n" +
" rdfs:range coin:Coin.\n" +
"coin:Mask a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 5;\n" +
" rdfs:range coin:Coin.\n"
if config.Behavior&token.Divisible == 0 {
schema += "coin:AdditionalReference a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 64;\n" +
" qcl:order 6;\n" +
" rdfs:range coin:Coin.\n"
schema += "coin:AdditionalReferenceKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 7;\n" +
" rdfs:range coin:Coin.\n"
}
if config.Behavior&token.Acceptable != 0 {
schema += "\npending:PendingTransaction a rdfs:Class;\n" +
" rdfs:label \"a pending transaction\".\n" +
"pending:FrameNumber a rdfs:Property;\n" +
" rdfs:domain qcl:Uint;\n" +
" qcl:size 8;\n" +
" qcl:order 0;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:Commitment a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 1;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:ToOneTimeKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 2;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:RefundOneTimeKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 3;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:ToVerificationKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 4;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:RefundVerificationKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 5;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:ToCoinBalance a rdfs:Property;\n" +
" rdfs:domain qcl:Uint;\n" +
" qcl:size 56;\n" +
" qcl:order 6;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:RefundCoinBalance a rdfs:Property;\n" +
" rdfs:domain qcl:Uint;\n" +
" qcl:size 56;\n" +
" qcl:order 7;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:ToMask a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 8;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:RefundMask a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 9;\n" +
" rdfs:range pending:PendingTransaction.\n"
if config.Behavior&token.Divisible == 0 {
schema += "pending:ToAdditionalReference a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 64;\n" +
" qcl:order 10;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:ToAdditionalReferenceKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 11;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:RefundAdditionalReference a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 64;\n" +
" qcl:order 12;\n" +
" rdfs:range pending:PendingTransaction.\n" +
"pending:RefundAdditionalReferenceKey a rdfs:Property;\n" +
" rdfs:domain qcl:ByteArray;\n" +
" qcl:size 56;\n" +
" qcl:order 13;\n" +
" rdfs:range pending:PendingTransaction.\n"
}
if config.Behavior&token.Expirable != 0 {
schema += "pending:Expiration a rdfs:Property;\n" +
" rdfs:domain qcl:Uint;\n" +
" qcl:size 8;\n"
if config.Behavior&token.Divisible == 0 {
schema += " qcl:order 14;\n"
} else {
schema += " qcl:order 10;\n"
}
schema += " rdfs:range pending:PendingTransaction.\n"
}
}
schema += "\n"
return schema, nil
}
type mockVertex struct {
mock.Mock
}
// Commit implements hypergraph.Vertex.
func (m *mockVertex) Commit(prover crypto.InclusionProver) []byte {
panic("unimplemented")
}
// GetAppAddress implements hypergraph.Vertex.
func (m *mockVertex) GetAppAddress() [32]byte {
panic("unimplemented")
}
// GetAtomType implements hypergraph.Vertex.
func (m *mockVertex) GetAtomType() hypergraph.AtomType {
panic("unimplemented")
}
// GetDataAddress implements hypergraph.Vertex.
func (m *mockVertex) GetDataAddress() [32]byte {
panic("unimplemented")
}
// GetID implements hypergraph.Vertex.
func (m *mockVertex) GetID() [64]byte {
panic("unimplemented")
}
// GetSize implements hypergraph.Vertex.
func (m *mockVertex) GetSize() *big.Int {
panic("unimplemented")
}
// ToBytes implements hypergraph.Vertex.
func (m *mockVertex) ToBytes() []byte {
panic("unimplemented")
}
type mockFrameValidator struct {
mock.Mock
}
func (m *mockFrameValidator) Validate(frame *protobufs.AppShardFrame) (bool, error) {
args := m.Called(frame)
return args.Bool(0), args.Error(1)
}
type mockDynamicFeeManager struct {
mock.Mock
}
func (m *mockDynamicFeeManager) AddFrameFeeVote(filter []byte, frameNumber uint64, feeMultiplierVote uint64) error {
args := m.Called(filter, frameNumber, feeMultiplierVote)
return args.Error(0)
}
func (m *mockDynamicFeeManager) GetNextFeeMultiplier(filter []byte) (uint64, error) {
args := m.Called(filter)
return args.Get(0).(uint64), args.Error(1)
}
func (m *mockDynamicFeeManager) GetVoteHistory(filter []byte) ([]uint64, error) {
args := m.Called(filter)
return args.Get(0).([]uint64), args.Error(1)
}
func (m *mockDynamicFeeManager) GetAverageWindowSize(filter []byte) (int, error) {
args := m.Called(filter)
return args.Int(0), args.Error(1)
}
func (m *mockDynamicFeeManager) PruneOldData(maxAge uint64) error {
args := m.Called(maxAge)
return args.Error(0)
}
func (m *mockDynamicFeeManager) RewindToFrame(filter []byte, frameNumber uint64) (int, error) {
args := m.Called(filter, frameNumber)
return args.Int(0), args.Error(1)
}
type mockGlobalFrameValidator struct {
mock.Mock
}
func (m *mockGlobalFrameValidator) Validate(frame *protobufs.GlobalFrame) (bool, error) {
args := m.Called(frame)
return args.Bool(0), args.Error(1)
}
func createTestGlobalConsensusEngine(t *testing.T) (
*global.GlobalConsensusEngine,
*mockPubSub,
*mockGlobalFrameValidator,
*mocks.MockDifficultyAdjuster,
*mocks.MockEventDistributor,
*consensustime.GlobalTimeReel,
) {
logger := zap.NewNop()
config := &config.Config{
Engine: &config.EngineConfig{
Difficulty: 100,
},
P2P: &config.P2PConfig{
Network: 99,
},
}
// Create mocks
pubsub := newMockPubSub([]byte{0x01, 0x02, 0x03, 0x04})
hypergraph := &mocks.MockHypergraph{}
keyManager := &mocks.MockKeyManager{}
keyStore := &mocks.MockKeyStore{}
clockStore := &mocks.MockClockStore{}
frameProver := &mocks.MockFrameProver{}
inclusionProver := &mocks.MockInclusionProver{}
signerRegistry := &mocks.MockSignerRegistry{}
proverRegistry := &mocks.MockProverRegistry{}
dynamicFeeManager := &mockDynamicFeeManager{}
appFrameValidator := new(mockFrameValidator)
frameValidator := &mockGlobalFrameValidator{}
difficultyAdjuster := &mocks.MockDifficultyAdjuster{}
rewardIssuance := &mocks.MockRewardIssuance{}
eventDistributor := &mocks.MockEventDistributor{}
// Create time reel
globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, proverRegistry, clockStore, 99, true)
require.NoError(t, err)
eventDistributor.On("Start", mock.Anything).Return(nil)
eventDistributor.On("Subscribe", mock.Anything).Return(make(<-chan consensustypes.ControlEvent, 10))
eventDistributor.On("Unsubscribe", mock.Anything).Return()
eventDistributor.On("Stop").Return(nil)
proverRegistry.On("GetOrderedProvers", mock.Anything, mock.Anything).Return([][]byte{}, nil)
// Create mock signer with Public method
mockSigner := &mocks.MockBLSSigner{}
mockSigner.On("Public").Return(make([]byte, 585))
mockSigner.On("SignWithDomain", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
keyManager.On("GetSigningKey", mock.Anything).Return(mockSigner, nil)
keyManager.On("GetRawKey", mock.Anything).Return(&tkeys.Key{
Type: crypto.KeyTypeBLS48581G1,
PublicKey: make([]byte, 585),
}, nil)
// Create engine
engine, err := global.NewGlobalConsensusEngine(
logger,
config,
1000, // frameTimeMillis
pubsub,
hypergraph,
keyManager,
keyStore,
frameProver,
inclusionProver,
signerRegistry,
proverRegistry,
dynamicFeeManager,
appFrameValidator,
frameValidator,
difficultyAdjuster,
rewardIssuance,
eventDistributor,
globalTimeReel,
nil,
nil,
nil,
nil,
nil,
nil,
&mockEncryptedChannel{},
&mocks.MockBulletproofProver{},
&mocks.MockVerifiableEncryptor{},
&mocks.MockDecafConstructor{},
&mocks.MockCompiler{},
nil,
p2p.NewInMemoryPeerInfoManager(logger),
)
require.NoError(t, err)
return engine, pubsub, frameValidator, difficultyAdjuster, eventDistributor, globalTimeReel
}
// createTestProverRegistry creates a mock ProverRegistry that returns expected provers
func createTestProverRegistry() *mocks.MockProverRegistry {
proverRegistry := new(mocks.MockProverRegistry)
proverRegistry.On("GetNextProver", mock.Anything, mock.Anything).Return([]byte{0x01, 0x02, 0x03, 0x04}, nil)
proverRegistry.On("GetOrderedProvers", mock.Anything, mock.Anything).Return([][]byte{{0x01, 0x02, 0x03, 0x04}}, nil)
return proverRegistry
}
func createTestAppTimeReel(
t *testing.T,
appAddress []byte,
clockStore store.ClockStore,
) *consensustime.AppTimeReel {
logger := zap.NewNop()
proverRegistry := createTestProverRegistry()
appTimeReel, err := consensustime.NewAppTimeReel(logger, appAddress, proverRegistry, clockStore, true)
require.NoError(t, err)
return appTimeReel
}
func createTestAppConsensusEngine(
t *testing.T,
) (
*app.AppConsensusEngine,
*mockPubSub,
*mockFrameValidator,
*mocks.MockDifficultyAdjuster,
*mocks.MockEventDistributor,
*consensustime.AppTimeReel,
) {
logger := zap.NewNop()
config := &config.Config{
Engine: &config.EngineConfig{
Difficulty: 100,
},
P2P: &config.P2PConfig{
Network: 99,
},
DB: &config.DBConfig{
InMemoryDONOTUSE: true,
Path: ".test/test_store",
},
}
appAddress := []byte{0x01, 0x02, 0x03}
mockPubSub := newMockPubSub([]byte{0x01, 0x02, 0x03, 0x04})
mockHypergraph := new(mocks.MockHypergraph)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyStore := new(mocks.MockKeyStore)
mockFrameProver := new(mocks.MockFrameProver)
mockInclusionProver := new(mocks.MockInclusionProver)
mockSignerRegistry := new(mocks.MockSignerRegistry)
mockFrameValidator := new(mockFrameValidator)
mockDifficultyAdjuster := new(mocks.MockDifficultyAdjuster)
mockRewardIssuance := new(mocks.MockRewardIssuance)
mockEventDistributor := new(mocks.MockEventDistributor)
pebbleDB := pstore.NewPebbleDB(logger, config.DB, 0)
clockStore := pstore.NewPebbleClockStore(pebbleDB, logger)
inboxStore := pstore.NewPebbleInboxStore(pebbleDB, logger)
shardStore := pstore.NewPebbleShardsStore(pebbleDB, logger)
consensusStore := pstore.NewPebbleConsensusStore(pebbleDB, logger)
hypergraphStore := pstore.NewPebbleHypergraphStore(config.DB, pebbleDB, logger, &mocks.MockVerifiableEncryptor{}, mockInclusionProver)
appTimeReel := createTestAppTimeReel(t, appAddress, clockStore)
mockProverRegistry := createTestProverRegistry()
mockDynamicFeeManager := new(mockDynamicFeeManager)
// Create global time reel
globalTimeReel, err := consensustime.NewGlobalTimeReel(logger, mockProverRegistry, clockStore, 99, true)
require.NoError(t, err)
mockKey := &tkeys.Key{
Id: "q-prover-key",
Type: crypto.KeyTypeBLS48581G1,
PublicKey: make([]byte, 585),
PrivateKey: make([]byte, 74),
}
mockFrameProver.On("ProveFrameHeaderGenesis", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&protobufs.FrameHeader{
FrameNumber: 0,
Address: []byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
},
Output: make([]byte, 516),
Timestamp: 0,
Difficulty: 160000,
ParentSelector: make([]byte, 32),
RequestsRoot: make([]byte, 64),
StateRoots: make([][]byte, 4),
Prover: make([]byte, 32),
FeeMultiplierVote: 100,
}, nil)
mockEventDistributor.On("Start", mock.Anything).Return(nil)
mockEventDistributor.On("Subscribe", mock.Anything).Return(make(<-chan consensustypes.ControlEvent, 10))
mockEventDistributor.On("Unsubscribe", mock.Anything).Return()
mockEventDistributor.On("Stop").Return(nil)
mockSigner := new(mocks.MockBLSSigner)
mockSigner.On("Public").Return(make([]byte, 585))
mockSigner.On("Private").Return(make([]byte, 74))
mockKeyManager.On("GetSigningKey", "q-prover-key").Return(mockSigner, nil)
mockKeyManager.On("GetRawKey", "q-prover-key").Return(mockKey, nil)
mockDynamicFeeManager.On("AddFrameFeeVote", mock.Anything, mock.Anything, mock.Anything).Return(nil)
engine, err := app.NewAppConsensusEngine(
logger,
config,
1,
appAddress,
mockPubSub,
mockHypergraph,
mockKeyManager,
mockKeyStore,
clockStore,
inboxStore,
shardStore,
hypergraphStore,
consensusStore,
mockFrameProver,
mockInclusionProver,
&mocks.MockBulletproofProver{}, // bulletproofProver
&mocks.MockVerifiableEncryptor{}, // verEnc
&mocks.MockDecafConstructor{}, // decafConstructor
&mocks.MockCompiler{}, // compiler
mockSignerRegistry,
mockProverRegistry,
mockDynamicFeeManager,
mockFrameValidator,
&mockGlobalFrameValidator{},
mockDifficultyAdjuster,
mockRewardIssuance,
mockEventDistributor,
p2p.NewInMemoryPeerInfoManager(logger),
appTimeReel,
globalTimeReel,
&mocks.MockBlsConstructor{},
&mockEncryptedChannel{},
nil,
)
assert.NoError(t, err)
return engine,
mockPubSub,
mockFrameValidator,
mockDifficultyAdjuster,
mockEventDistributor,
appTimeReel
}
// mockPubSub extends the basic mock with app-specific features
type mockPubSub struct {
mock.Mock
mu sync.RWMutex
subscribers map[string][]func(message *pb.Message) error
validators map[string]func(peerID peer.ID, message *pb.Message) tp2p.ValidationResult
peerID []byte
peerCount int
networkPeers map[string]*mockPubSub
messageLog []messageRecord // Track all messages for debugging
globalFrames []*protobufs.GlobalFrame // Store frames for sync
appFrames []*protobufs.AppShardFrame // Store frames for sync
}
// GetOwnMultiaddrs implements tp2p.PubSub.
func (m *mockPubSub) GetOwnMultiaddrs() []multiaddr.Multiaddr {
panic("unimplemented")
}
// AddPeerScore implements tp2p.PubSub.
func (m *mockPubSub) AddPeerScore(peerId []byte, scoreDelta int64) {
panic("unimplemented")
}
// Bootstrap implements tp2p.PubSub.
func (m *mockPubSub) Bootstrap(ctx context.Context) error {
panic("unimplemented")
}
// DiscoverPeers implements tp2p.PubSub.
func (m *mockPubSub) DiscoverPeers(ctx context.Context) error {
panic("unimplemented")
}
// GetDirectChannel implements tp2p.PubSub.
func (m *mockPubSub) GetDirectChannel(ctx context.Context, peerId []byte, purpose string) (*grpc.ClientConn, error) {
panic("unimplemented")
}
// GetMultiaddrOfPeer implements tp2p.PubSub.
func (m *mockPubSub) GetMultiaddrOfPeer(peerId []byte) string {
panic("unimplemented")
}
// GetMultiaddrOfPeerStream implements tp2p.PubSub.
func (m *mockPubSub) GetMultiaddrOfPeerStream(ctx context.Context, peerId []byte) <-chan multiaddr.Multiaddr {
panic("unimplemented")
}
// GetNetwork implements tp2p.PubSub.
func (m *mockPubSub) GetNetwork() uint {
panic("unimplemented")
}
// GetNetworkPeersCount implements tp2p.PubSub.
func (m *mockPubSub) GetNetworkPeersCount() int {
panic("unimplemented")
}
// GetPeerScore implements tp2p.PubSub.
func (m *mockPubSub) GetPeerScore(peerId []byte) int64 {
panic("unimplemented")
}
// GetPublicKey implements tp2p.PubSub.
func (m *mockPubSub) GetPublicKey() []byte {
panic("unimplemented")
}
// GetRandomPeer implements tp2p.PubSub.
func (m *mockPubSub) GetRandomPeer(bitmask []byte) ([]byte, error) {
panic("unimplemented")
}
// IsPeerConnected implements tp2p.PubSub.
func (m *mockPubSub) IsPeerConnected(peerId []byte) bool {
panic("unimplemented")
}
// Publish implements tp2p.PubSub.
func (m *mockPubSub) Publish(address []byte, data []byte) error {
panic("unimplemented")
}
// Reachability implements tp2p.PubSub.
func (m *mockPubSub) Reachability() *wrapperspb.BoolValue {
panic("unimplemented")
}
// Reconnect implements tp2p.PubSub.
func (m *mockPubSub) Reconnect(peerId []byte) error {
panic("unimplemented")
}
// SetPeerScore implements tp2p.PubSub.
func (m *mockPubSub) SetPeerScore(peerId []byte, score int64) {
panic("unimplemented")
}
// SignMessage implements tp2p.PubSub.
func (m *mockPubSub) SignMessage(msg []byte) ([]byte, error) {
panic("unimplemented")
}
// StartDirectChannelListener implements tp2p.PubSub.
func (m *mockPubSub) StartDirectChannelListener(key []byte, purpose string, server *grpc.Server) error {
panic("unimplemented")
}
type messageRecord struct {
timestamp time.Time
from []byte
to []byte
data []byte
}
func newMockPubSub(peerID []byte) *mockPubSub {
return &mockPubSub{
subscribers: make(map[string][]func(message *pb.Message) error),
validators: make(map[string]func(peerID peer.ID, message *pb.Message) tp2p.ValidationResult),
peerID: peerID,
peerCount: 10,
networkPeers: make(map[string]*mockPubSub),
messageLog: make([]messageRecord, 0),
globalFrames: make([]*protobufs.GlobalFrame, 0),
appFrames: make([]*protobufs.AppShardFrame, 0),
}
}
func (m *mockPubSub) Subscribe(bitmask []byte, handler func(message *pb.Message) error) error {
m.mu.Lock()
defer m.mu.Unlock()
key := string(bitmask)
m.subscribers[key] = append(m.subscribers[key], handler)
return nil
}
func (m *mockPubSub) PublishToBitmask(bitmask []byte, data []byte) error {
m.mu.Lock()
m.messageLog = append(m.messageLog, messageRecord{
timestamp: time.Now(),
from: m.peerID,
to: bitmask,
data: data,
})
// If this is an app frame, store it for sync
if len(bitmask) >= 4 && bitmask[0] != 0x01 { // Not a message bitmask
frame := &protobufs.AppShardFrame{}
if err := proto.Unmarshal(data, frame); err == nil {
m.appFrames = append(m.appFrames, frame)
}
}
m.mu.Unlock()
message := &pb.Message{
Data: data,
From: m.peerID,
}
// Deliver to local subscribers
m.mu.RLock()
handlers := m.subscribers[string(bitmask)]
m.mu.RUnlock()
for _, handler := range handlers {
go handler(message)
}
// Deliver to network peers
m.mu.RLock()
peers := make([]*mockPubSub, 0, len(m.networkPeers))
for _, peer := range m.networkPeers {
if peer != m {
peers = append(peers, peer)
}
}
m.mu.RUnlock()
for _, peer := range peers {
// Deliver synchronously to ensure proper ordering
peer.receiveFromNetwork(bitmask, message)
}
return nil
}
func (m *mockPubSub) receiveFromNetwork(bitmask []byte, message *pb.Message) {
m.mu.RLock()
validator := m.validators[string(bitmask)]
m.mu.RUnlock()
if validator != nil {
result := validator(peer.ID(message.From), message)
if result != tp2p.ValidationResultAccept {
// Log validation rejection for debugging
frame := &protobufs.AppShardFrame{}
if err := proto.Unmarshal(message.Data, frame); err == nil && frame.Header != nil {
fmt.Printf("DEBUG: Node %x rejected frame %d from %x (validation result: %v)\n",
m.peerID[:4], frame.Header.FrameNumber, message.From[:4], result)
}
return
}
}
m.mu.RLock()
handlers := m.subscribers[string(bitmask)]
m.mu.RUnlock()
for _, handler := range handlers {
go handler(message) // Make async to match PublishToBitmask behavior
}
}
func (m *mockPubSub) RegisterValidator(bitmask []byte, validator func(peerID peer.ID, message *pb.Message) tp2p.ValidationResult, sync bool) error {
m.mu.Lock()
defer m.mu.Unlock()
m.validators[string(bitmask)] = validator
return nil
}
func (m *mockPubSub) GetPeerstoreCount() int {
return m.peerCount
}
func (m *mockPubSub) GetPeerID() []byte {
return m.peerID
}
func (m *mockPubSub) Unsubscribe(bitmask []byte, raw bool) {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.subscribers, string(bitmask))
}
func (m *mockPubSub) UnregisterValidator(bitmask []byte) error {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.validators, string(bitmask))
return nil
}
func (m *mockPubSub) GetNetworkInfo() *protobufs.NetworkInfoResponse {
return &protobufs.NetworkInfoResponse{}
}
type mockTransaction struct{}
// Abort implements store.Transaction.
func (m *mockTransaction) Abort() error {
return nil
}
// Commit implements store.Transaction.
func (m *mockTransaction) Commit() error {
return nil
}
// Delete implements store.Transaction.
func (m *mockTransaction) Delete(key []byte) error {
panic("unimplemented")
}
// DeleteRange implements store.Transaction.
func (m *mockTransaction) DeleteRange(lowerBound []byte, upperBound []byte) error {
panic("unimplemented")
}
// Get implements store.Transaction.
func (m *mockTransaction) Get(key []byte) ([]byte, io.Closer, error) {
panic("unimplemented")
}
// NewIter implements store.Transaction.
func (m *mockTransaction) NewIter(lowerBound []byte, upperBound []byte) (store.Iterator, error) {
panic("unimplemented")
}
// Set implements store.Transaction.
func (m *mockTransaction) Set(key []byte, value []byte) error {
return nil
}
// setupTokenIntrinsicMocks sets up token intrinsic mocks for payment verification
func setupTokenIntrinsicMocks(
t *testing.T,
mockHG *mocks.MockHypergraph,
) {
// For payment transactions, we need to use the QUIL token address
tokenDomain := token.QUIL_TOKEN_ADDRESS
// Set up token intrinsic metadata mock for this specific domain
tokenMetadataAddress := slices.Concat(tokenDomain, bytes.Repeat([]byte{0xff}, 32))
tokenMetadataTree := &tries.VectorCommitmentTree{}
// Create a mock vertex for token metadata
tokenMockVertex := &mockVertex{}
tokenMockVertex.On("GetAddress").Return(tokenMetadataAddress)
tokenMockVertex.On("GetData").Return(tokenMetadataTree, nil)
// Set up the mock expectations
mockHG.On("GetVertex", [64]byte(tokenMetadataAddress)).Return(tokenMockVertex, nil).Maybe()
mockHG.On("GetVertexData", [64]byte(tokenMetadataAddress)).Return(tokenMetadataTree, nil).Maybe()
}
// setupComputeMocks sets up the common mocks for compute execution engine tests
func setupComputeMocks(
t *testing.T,
mockHG *mocks.MockHypergraph,
mockInclusionProver *mocks.MockInclusionProver,
mockBulletproofProver *mocks.MockBulletproofProver,
engineMode engines.ExecutionMode,
) {
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil)
mockHG.On("GetProver").Return(mockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{})
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil)
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
// Add mock for multiproof creation
mockMultiproof := new(mocks.MockMultiproof)
mockMultiproof.On("FromBytes", mock.Anything).Return(nil)
mockMultiproof.On("Size").Return(0).Maybe()
mockMultiproof.On("ComputeSize").Return(0).Maybe()
mockMultiproof.On("Bind", mock.Anything).Return(nil).Maybe()
mockMultiproof.On("Prove", mock.Anything).Return(nil).Maybe()
mockMultiproof.On("Reset").Return(nil).Maybe()
mockMultiproof.On("Commit", mock.Anything).Return([]byte{}, nil).Maybe()
mockMultiproof.On("Verify", mock.Anything, mock.Anything).Return(true, nil).Maybe()
mockMultiproof.On("ProveMultiple", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{}, nil).Maybe()
mockInclusionProver.On("NewMultiproof").Return(mockMultiproof)
// Don't set up the GlobalMode metadata check here - let each test handle it
// based on whether it's before or after deployment
// Set up a generic mock for any GetVertex calls (for code deployment addresses)
mockHG.On("GetVertex", mock.Anything).Return(nil, nil).Maybe()
// Set up a generic mock for code deployment GetVertexData that matches the pattern
// Create the tree once to reuse
code := []byte("package main\n\nfunc main(a, b int) int { return a + b }")
codeTree := &tries.VectorCommitmentTree{}
codeTree.Insert([]byte{0 << 2}, code, nil, big.NewInt(int64(len(code))))
// This will match any 64-byte address that has "app" in it after byte 32
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if the address contains "app" starting from byte 32
for i := 32; i < 64-2; i++ {
if addr[i] == 'a' && addr[i+1] == 'p' && addr[i+2] == 'p' {
return true
}
}
return false
})).Return(codeTree, nil).Maybe()
}
// setupCodeDeploymentData sets up mock data for deployed code
func setupCodeDeploymentData(
t *testing.T,
mockHG *mocks.MockHypergraph,
domain []byte,
codeAddress []byte,
) {
// Create a 64-byte address from the code address
var addr64 [64]byte
copy(addr64[:], domain)
copy(addr64[32:], codeAddress)
// Set up code deployment data
code := []byte("package main\n\nfunc main(a, b int) int { return a + b }")
err := tests.SetHypergraphCodeData(mockHG, addr64[:], code)
require.NoError(t, err)
}
// setupGlobalModePreDeploymentMocks sets up the mock for GlobalMode before deployment
func setupGlobalModePreDeploymentMocks(
mockHG *mocks.MockHypergraph,
domain []byte,
) {
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
// Before deployment, the metadata vertex doesn't exist
mockHG.On("GetVertex", [64]byte(metadataAddress)).Return(nil, store.ErrNotFound)
}
// setupComputeMetadata sets up the compute metadata after deployment
func setupComputeMetadata(
t *testing.T,
mockHG *mocks.MockHypergraph,
domain []byte,
readKey []byte,
writeKey []byte,
) {
// Use provided keys for metadata
rdfSchema := `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.
`
// After deployment is done, set up the metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
err := tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
}
// Calling this test "just" a test for compute execution engine is a bit of a
// misnomer, because it involves a lot of moving pieces that need to occur in a
// specific order: The global execution engine needs to handle the deployment,
// allocate provers, verify the payment for the fee (for deployment and
// execution), and then the app execution engine has to consume the deployment,
// settle the metadata for it, process the rdf bundle (for hypergraph
// settlement), verify the payment for the execution fee, and handle the close
// out of the execution for fee dispatch. It is by far the most integration-y
// unit test we have. Like FAA guidelines, this test is written in the blood of
// past failures. Heed the failures like hard rules, and if you're questioning
// whether the test is wrong, you probably haven't bled enough.
func TestComputeExecutionEngine_ProcessMessage_DeployWithPaymentAndExecute(
t *testing.T,
) {
// Helper function to perform deployment steps with specific keys
performDeploymentWithKeys := func(t *testing.T, engine *engines.ComputeExecutionEngine, mockHG *mocks.MockHypergraph, mockCompiler *mocks.MockCompiler, readKey, writeKey []byte, engineMode engines.ExecutionMode) []byte {
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
// Use provided keys
outFees := []*big.Int{big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
// Deploy RDF schema with keys
args := compute.ComputeDeploy{
Config: &compute.ComputeIntrinsicConfiguration{
ReadPublicKey: readKey,
WritePublicKey: writeKey,
},
RDFSchema: []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.
`),
}
deploy := &protobufs.MessageRequest{
Request: &protobufs.MessageRequest_ComputeDeploy{
ComputeDeploy: args.ToProtobuf(),
},
}
bundle := &protobufs.MessageBundle{
Requests: []*protobufs.MessageRequest{
payment,
deploy,
},
}
bundleBytes, err := bundle.ToCanonicalBytes()
require.NoError(t, err)
deployHash := sha3.Sum256(bundleBytes)
msg := &protobufs.Message{
Address: compute.COMPUTE_INTRINSIC_DOMAIN[:],
Hash: deployHash[:],
Payload: bundleBytes,
}
state := hgstate.NewHypergraphState(mockHG)
result, err := engine.ProcessMessage(0, big.NewInt(0), msg.Address, msg.Payload, state)
require.NoError(t, err)
ch := state.Changeset()
domain := ch[0].Domain
require.Len(t, result.Messages, 0)
mockCircuit := &mocks.MockCompiledCircuit{}
mockCircuit.On("Marshal", mock.Anything).Return(nil)
mockCompiler.On("Compile", mock.Anything, mock.Anything).Return(mockCircuit, nil)
mockCompiler.On("ValidateCircuit", mock.Anything).Return(nil)
// In GlobalMode, code deployment is not allowed after RDF schema deployment
if engineMode != engines.GlobalMode {
// Deploy code
sourceCode := []byte("package main\n\nfunc main(a, b int) int { return a + b }")
deployment, err := compute.NewCodeDeployment(
[32]byte(domain),
sourceCode,
[2]string{"qcl:Int", "qcl:Int"},
[2][]int{{4}, {4}},
[]string{"qcl:Int"},
mockCompiler,
)
require.NoError(t, err)
err = deployment.Prove(1)
require.NoError(t, err)
// Wrap in MessageRequest
deploy := &protobufs.MessageRequest{
Request: &protobufs.MessageRequest_CodeDeploy{
CodeDeploy: deployment.ToProtobuf(),
},
}
outFees := []*big.Int{big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
bundle := &protobufs.MessageBundle{
Requests: []*protobufs.MessageRequest{
payment,
deploy,
},
}
bundleBytes, err = bundle.ToCanonicalBytes()
require.NoError(t, err)
deployHash := sha3.Sum256(bundleBytes)
msg = &protobufs.Message{
Address: domain,
Hash: deployHash[:],
Payload: bundleBytes,
}
result, err = engine.ProcessMessage(0, big.NewInt(0), msg.Address, msg.Payload, result.State)
require.NoError(t, err)
err = result.State.Commit()
require.NoError(t, err)
}
return domain
}
performBundledDeploymentAndExecution := func(
t *testing.T,
engine *engines.ComputeExecutionEngine,
mockHG *mocks.MockHypergraph,
domain []byte,
mockCompiler *mocks.MockCompiler,
readKey, writeKey []byte,
operations []*compute.ExecuteOperation,
) ([]*protobufs.Message, error) {
// Set up mock circuit for code deployment
mockCircuit := &mocks.MockCompiledCircuit{}
mockCircuit.On("Marshal", mock.Anything).Return(nil)
mockCompiler.On("Compile", mock.Anything, mock.Anything).Return(mockCircuit, nil)
mockCompiler.On("ValidateCircuit", mock.Anything).Return(nil)
// Create source code for deployment
sourceCode := []byte("package main\n\nfunc main(a, b int) int { return a + b }")
// Create bundled message with all operations
bundledMsg := createCompleteBundleWithPayment(
t,
mockHG,
domain,
readKey,
writeKey,
sourceCode,
mockCompiler,
operations,
)
state := hgstate.NewHypergraphState(mockHG)
// Process the bundled message
result, err := engine.ProcessMessage(0, big.NewInt(0), bundledMsg.Address, bundledMsg.Payload, state)
if err != nil {
return nil, err
}
if err = state.Commit(); err != nil {
return nil, err
}
return result.Messages, nil
}
performDeployment := func(t *testing.T, engine *engines.ComputeExecutionEngine, mockHG *mocks.MockHypergraph, mockCompiler *mocks.MockCompiler, engineMode engines.ExecutionMode) []byte {
// Generate random keys
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
return domain
}
createTestCodeExecuteMessage := func(t *testing.T, mockHG *mocks.MockHypergraph, domain []byte, operations []*compute.ExecuteOperation) (*protobufs.Message, *compute.CodeExecute) {
var rendezvous [32]byte
rand.Read(rendezvous[:])
// Create valid payment transaction using protobuf
outFees := []*big.Int{big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
paymentTxBytes, err := payment.GetPendingTransaction().ToCanonicalBytes()
secretKey := make([]byte, 32)
rand.Read(secretKey)
ce := compute.NewCodeExecute(
[32]byte(domain),
paymentTxBytes,
secretKey,
rendezvous,
operations,
nil, nil, nil, nil, nil, nil, // Mock dependencies will be set by the engine
)
// Set up proof of payment
ce.ProofOfPayment[0] = paymentTxBytes
ce.ProofOfPayment[1] = make([]byte, 112) // Ed448 signature size
rand.Read(ce.ProofOfPayment[1])
// Wrap in MessageBundle and serialize
executeReq := &protobufs.MessageRequest{
Request: &protobufs.MessageRequest_CodeExecute{
CodeExecute: ce.ToProtobuf(),
},
}
bundle := &protobufs.MessageBundle{
Requests: []*protobufs.MessageRequest{
payment,
executeReq,
},
}
ceBytes, err := bundle.ToCanonicalBytes()
require.NoError(t, err)
// Create message
hash := sha3.Sum256(ceBytes)
require.NoError(t, err)
msg := &protobufs.Message{
Address: domain,
Hash: hash[:],
Payload: ceBytes,
}
return msg, ce
}
// Helper function to create a test CodeFinalize message
createTestCodeFinalizeMessage := func(t *testing.T, domain []byte, writePrivKey []byte, config *compute.ComputeIntrinsicConfiguration, rendezvous [32]byte, results []*compute.ExecutionResult, mockHG *mocks.MockHypergraph, keyManager *mocks.MockKeyManager) (*protobufs.Message, *compute.CodeFinalize) {
cf := compute.NewCodeFinalize(
rendezvous,
[32]byte(domain),
results,
[]*compute.StateTransition{},
[]byte("message_output"),
writePrivKey,
config,
nil, nil, nil, nil, nil, keyManager, // Mock dependencies
)
err := cf.Prove(1)
require.NoError(t, err)
// Create valid payment transaction using protobuf
outFees := []*big.Int{big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
// Wrap in MessageRequest and serialize
finalizeReq := &protobufs.MessageRequest{
Request: &protobufs.MessageRequest_CodeFinalize{
CodeFinalize: cf.ToProtobuf(),
},
}
bundle := &protobufs.MessageBundle{
Requests: []*protobufs.MessageRequest{
payment,
finalizeReq,
},
}
cfBytes, err := bundle.ToCanonicalBytes()
require.NoError(t, err)
// Create message
hash := sha3.Sum256(cfBytes)
require.NoError(t, err)
msg := &protobufs.Message{
Address: domain,
Hash: hash[:],
Payload: cfBytes,
}
return msg, cf
}
// Test execution modes
type TestExecutionMode int
const (
TestGlobalMode TestExecutionMode = iota
TestApplicationMode
TestMixedMode
)
// Helper function to run test with all three execution modes
runTestWithAllModes := func(t *testing.T, testName string, testFunc func(t *testing.T, mode TestExecutionMode)) {
modes := []struct {
name string
mode TestExecutionMode
}{
{"global_must_sequence", TestGlobalMode},
{"app_fully_sequences", TestApplicationMode},
{"global_sequences_payment_and_partial_execute", TestMixedMode},
}
for _, mode := range modes {
t.Run(mode.name, func(t *testing.T) {
testFunc(t, mode.mode)
})
}
}
// Helper function to assert code execution results based on mode
assertCodeExecutionResult := func(t *testing.T, mode TestExecutionMode, msgs *execution.ProcessMessageResult, err error, shouldError bool) {
// In GlobalMode, after deployment, only deploy messages are allowed
if mode == TestGlobalMode {
assert.Error(t, err)
assert.Contains(t, err.Error(), "non-deploy messages not allowed in global mode")
assert.Nil(t, msgs)
} else {
if shouldError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.NotNil(t, msgs)
if msgs != nil && msgs.State != nil {
err = msgs.State.Commit()
assert.NoError(t, err)
}
}
}
}
// Helper function to assert bundled execution results
assertBundledExecutionResult := func(t *testing.T, msgs []*protobufs.Message, err error) {
// Bundled operations should work in all modes, including GlobalMode
if err != nil {
// If there's an error, it should not be the global mode restriction
assert.NotContains(t, err.Error(), "non-deploy messages not allowed in global mode",
"Bundled operations should bypass global mode restriction")
}
}
// Test 1: Valid single operation no dependencies
t.Run("valid_single_operation_no_dependencies", func(t *testing.T) {
runTestWithAllModes(t, "valid_single_operation_no_dependencies", func(t *testing.T, mode TestExecutionMode) {
// Create test dependencies
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create single operation with no dependencies
op := &compute.ExecuteOperation{
Application: compute.Application{
Address: makeExtrinsicAddress("test_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, []*compute.ExecuteOperation{op})
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
if engineMode == engines.GlobalMode {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assertCodeExecutionResult(t, mode, msgs, err, false)
}
})
})
// Test 1b: Valid single operation using bundled approach (works in GlobalMode)
t.Run("valid_single_operation_bundled", func(t *testing.T) {
runTestWithAllModes(t, "valid_single_operation_bundled", func(t *testing.T, mode TestExecutionMode) {
// Create test dependencies
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Create single operation
op := &compute.ExecuteOperation{
Application: compute.Application{
Address: makeExtrinsicAddress("test_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
}
domain := make([]byte, 32)
rand.Read(domain)
// Use bundled approach
msgs, err := performBundledDeploymentAndExecution(
t, engine, mockHG, domain, mockCompiler,
readKey, writeKey,
[]*compute.ExecuteOperation{op},
)
// Bundled operations should work in all modes
assertBundledExecutionResult(t, msgs, err)
// In GlobalMode, this should succeed with bundling
if engineMode == engines.GlobalMode && err == nil {
assert.NotNil(t, msgs, "Bundled operations should produce responses in GlobalMode")
}
})
})
// Test 2: Valid multiple operations sequential dependencies
t.Run("valid_multiple_operations_sequential_dependencies", func(t *testing.T) {
runTestWithAllModes(t, "valid_multiple_operations_sequential_dependencies", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Create operations with sequential dependencies: op1 -> op2 -> op3
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("test_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{[]byte("op2")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("test_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{[]byte("op1")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("test_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 3: Valid multiple operations parallel execution
t.Run("valid_multiple_operations_parallel_execution", func(t *testing.T) {
runTestWithAllModes(t, "valid_multiple_operations_parallel_execution", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations with no dependencies (can run in parallel)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app1"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app2"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app3"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 4: Valid diamond dependency pattern
t.Run("valid_diamond_dependency_pattern", func(t *testing.T) {
runTestWithAllModes(t, "valid_diamond_dependency_pattern", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create diamond pattern: op1 -> op2, op3 -> op4
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{[]byte("op1")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{[]byte("op1")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op4"),
Dependencies: [][]byte{[]byte("op2"), []byte("op3")},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 5: Invalid circular dependency detection
t.Run("invalid_circular_dependency_detection", func(t *testing.T) {
runTestWithAllModes(t, "invalid_circular_dependency_detection", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
domain := make([]byte, 32)
rand.Read(domain)
// Ensure compute metadata is available
setupComputeMetadata(t, mockHG, domain, []byte{}, []byte{})
// Set up mocks
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
// Create circular dependency: op1 -> op2 -> op3 -> op1
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{[]byte("op3")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{[]byte("op1")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{[]byte("op2")},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message should fail
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assert.Error(t, err)
assert.Nil(t, msgs)
})
})
// Test 6: Invalid missing dependency reference
t.Run("invalid_missing_dependency_reference", func(t *testing.T) {
runTestWithAllModes(t, "invalid_missing_dependency_reference", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
// Create operations with missing dependency reference
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{[]byte("missing_op")}, // Reference to non-existent operation
},
}
domain := make([]byte, 32)
rand.Read(domain)
// Ensure compute metadata is available
setupComputeMetadata(t, mockHG, domain, []byte{}, []byte{})
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message should fail because compute intrinsic hasn't been deployed
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assert.Error(t, err)
assert.Nil(t, msgs)
})
})
// Test 7: Invalid payment proof rejected
t.Run("invalid_payment_proof_rejected", func(t *testing.T) {
runTestWithAllModes(t, "invalid_payment_proof_rejected", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks - payment validation fails
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(false)
// Additional mocks for payment transaction verification
mockMultiproof := &mocks.MockMultiproof{}
mockInclusionProver.On("NewMultiproof").Return(mockMultiproof, nil).Maybe()
mockMultiproof.On("Size").Return(0).Maybe()
mockMultiproof.On("ComputeSize").Return(0).Maybe()
mockMultiproof.On("Bind", mock.Anything).Return(nil).Maybe()
mockMultiproof.On("Prove", mock.Anything).Return(nil).Maybe()
mockMultiproof.On("Reset").Return(nil).Maybe()
mockMultiproof.On("Commit", mock.Anything).Return([]byte{}, nil).Maybe()
mockMultiproof.On("Verify", mock.Anything, mock.Anything).Return(true, nil).Maybe()
mockMultiproof.On("FromBytes", mock.Anything).Return(nil).Maybe()
mockMultiproof.On("ProveMultiple", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{}, nil).Maybe()
// Setup GetProver mock for deployment
mockHG.On("GetProver").Return(mockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
// Setup transaction mocks for deployment
mockTxn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(mockTxn, nil)
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil)
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
// Generate keys and set up metadata before deployment
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Add catch-all for any other GetVertex calls during deployment
mockHG.On("GetVertex", mock.Anything).Return(nil, fmt.Errorf("not found")).Maybe()
// Perform deployment
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message should fail
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assert.Error(t, err)
// In global mode, the error is different because non-deploy messages are not allowed
if engineMode == engines.GlobalMode {
assert.Contains(t, err.Error(), "non-deploy messages not allowed in global mode")
} else {
// Payment validation fails with "invalid signature" error
assert.Contains(t, err.Error(), "invalid signature")
}
assert.Nil(t, msgs)
})
})
// Test 8: Invalid payment insufficient amount
t.Run("invalid_payment_insufficient_amount", func(t *testing.T) {
runTestWithAllModes(t, "invalid_payment_insufficient_amount", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create mock agreements - the New() method creates with random keys
mockDecafConstructor := &mocks.MockDecafConstructor{}
vk, _ := mockDecafConstructor.New()
sk, _ := mockDecafConstructor.New()
out1, err := token.NewPendingTransactionOutput(big.NewInt(9), vk.Public(), sk.Public(), vk.Public(), sk.Public(), 0)
if err != nil {
t.Fatal(err)
}
mockKeyManager.On("GetAgreementKey", "q-view-key").Return(&mocks.MockDecafAgreement{}, nil)
mockKeyManager.On("GetAgreementKey", "q-spend-key").Return(&mocks.MockDecafAgreement{}, nil)
address1 := [64]byte{}
copy(address1[:32], token.QUIL_TOKEN_ADDRESS)
rand.Read(address1[32:])
address2 := [64]byte{}
copy(address2[:32], token.QUIL_TOKEN_ADDRESS)
rand.Read(address2[32:])
tree1 := &tries.VectorCommitmentTree{}
otk1 := make([]byte, 56)
comm1 := make([]byte, 56)
mask1 := make([]byte, 56)
verifkey1 := make([]byte, 56)
rand.Read(otk1)
rand.Read(comm1)
rand.Read(mask1)
rand.Read(verifkey1)
maskedCoinBalanceBytes1 := make([]byte, 56)
rand.Read(maskedCoinBalanceBytes1)
tree1.Insert([]byte{0}, binary.BigEndian.AppendUint64(nil, token.FRAME_2_1_EXTENDED_ENROLL_CONFIRM_END+1), nil, big.NewInt(8))
tree1.Insert([]byte{1 << 2}, comm1, nil, big.NewInt(56))
tree1.Insert([]byte{2 << 2}, otk1, nil, big.NewInt(56))
tree1.Insert([]byte{3 << 2}, verifkey1, nil, big.NewInt(56))
tree1.Insert([]byte{4 << 2}, maskedCoinBalanceBytes1, nil, big.NewInt(56))
tree1.Insert([]byte{5 << 2}, mask1, nil, big.NewInt(56))
typeAddr, _ := hex.DecodeString("096de9a09f693f92cfa9cf3349bab2b3baee09f3e4f9c596514ecb3e8b0dff8f")
tree1.Insert(bytes.Repeat([]byte{0xff}, 32), typeAddr, nil, big.NewInt(32))
mockHG.On("GetVertex", [64]byte(slices.Concat(token.QUIL_TOKEN_ADDRESS, address1[32:]))).Return(&mockVertex{}, nil)
mockHG.On("GetVertexData", [64]byte(slices.Concat(token.QUIL_TOKEN_ADDRESS, address1[32:]))).Return(tree1, nil)
// simulate input as commitment to total
input1, _ := token.NewPendingTransactionInput(address1[:])
tokenconfig := &token.TokenIntrinsicConfiguration{
Behavior: token.Mintable | token.Burnable | token.Divisible | token.Acceptable | token.Expirable | token.Tenderable,
MintStrategy: &token.TokenMintStrategy{
MintBehavior: token.MintWithProof,
ProofBasis: token.ProofOfMeaningfulWork,
},
Units: big.NewInt(8000000000),
Name: "QUIL",
Symbol: "QUIL",
}
rdfSchema, _ := prepareRDFSchemaFromConfig(token.QUIL_TOKEN_ADDRESS, tokenconfig)
parser := &schema.TurtleRDFParser{}
rdfMultiprover := schema.NewRDFMultiprover(parser, mockInclusionProver)
mockPaymentTx := token.NewPendingTransaction(
[32]byte(token.QUIL_TOKEN_ADDRESS),
[]*token.PendingTransactionInput{input1},
[]*token.PendingTransactionOutput{out1},
[]*big.Int{},
tokenconfig,
mockHG,
mockBulletproofProver,
mockInclusionProver,
mockVerEnc,
mockDecaf,
keys.ToKeyRing(mockKeyManager, false),
rdfSchema,
rdfMultiprover,
)
// Additional mocks for transaction creation
// RangeProof needs to return a properly sized byte array
rangeProof := make([]byte, 112) // Typical range proof size
mockBulletproofProver.On("RangeProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(rangeProof, nil).Maybe()
// GenerateRangeProofFromBig needs to return a RangeProofResult struct
rangeProofResult := crypto.RangeProofResult{
Proof: rangeProof,
Commitment: make([]byte, 56),
Blinding: make([]byte, 56),
}
mockBulletproofProver.On("GenerateRangeProofFromBig", mock.Anything, mock.Anything, mock.Anything).Return(rangeProofResult, nil).Maybe()
mockBulletproofProver.On("SignHidden", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{}).Maybe()
// Add ProveMultiple mock directly to the inclusion prover for this test
mockMultiproof := new(mocks.MockMultiproof)
mockMultiproof.On("FromBytes", mock.Anything).Return(nil)
mockMultiproof.On("ToBytes").Return([]byte{}, nil)
mockInclusionProver.On("ProveMultiple", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(mockMultiproof).Maybe()
// Add CreateTraversalProof mock for the hypergraph
mockTraversalProofMultiproof := new(mocks.MockMultiproof)
// Create a properly sized multiproof byte array (74 bytes multicommitment + some proof data)
multiproofBytes := make([]byte, 148) // 74 for multicommitment + 74 for proof
rand.Read(multiproofBytes)
mockTraversalProofMultiproof.On("ToBytes").Return(multiproofBytes, nil)
mockTraversalProof := &tries.TraversalProof{
Multiproof: mockTraversalProofMultiproof,
SubProofs: []tries.TraversalSubProof{
{
Commits: [][]byte{make([]byte, 74)}, // At least one commit
Ys: [][]byte{make([]byte, 64)}, // Matching Ys
Paths: [][]uint64{{0}}, // At least one path
},
},
}
mockHG.On("CreateTraversalProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(mockTraversalProof, nil).Maybe()
// Call Prove to populate the transaction fields
err = mockPaymentTx.Prove(0)
require.NoError(t, err)
paymentTxBytes, err := mockPaymentTx.ToProtobuf().ToCanonicalBytes()
require.NoError(t, err)
// Create operations
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
var rendezvous [32]byte
rand.Read(rendezvous[:])
// Create CodeExecute with insufficient payment
ce := compute.NewCodeExecute(
[32]byte(domain),
paymentTxBytes,
[]byte("mock_secret_key"),
rendezvous,
ops,
mockHG, mockBulletproofProver, mockInclusionProver,
mockVerEnc, mockDecaf, mockKeyManager,
)
// Set up proof of payment
ce.ProofOfPayment[0] = paymentTxBytes
ce.ProofOfPayment[1] = []byte("mock_signature")
// Wrap in MessageRequest and serialize
executeReq := &protobufs.MessageRequest{
Request: &protobufs.MessageRequest_CodeExecute{
CodeExecute: ce.ToProtobuf(),
},
}
outFees := []*big.Int{big.NewInt(10000000)}
total := big.NewInt(1)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
bundle := &protobufs.MessageBundle{
Requests: []*protobufs.MessageRequest{
payment,
executeReq,
},
}
bundleBytes, err := bundle.ToCanonicalBytes()
require.NoError(t, err)
// Create message
hash := sha3.Sum256(bundleBytes)
require.NoError(t, err)
msg := &protobufs.Message{
Address: domain,
Hash: hash[:],
Payload: bundleBytes,
}
// Process message should fail
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(1000), msg.Address, msg.Payload, state)
assert.Error(t, err)
// Don't let the error check panic
if err != nil {
// In GlobalMode, it fails with global mode restriction
// In other modes, it should fail with insufficient payment
if engineMode == engines.GlobalMode {
assert.Contains(t, err.Error(), "non-deploy messages not allowed in global mode")
} else {
assert.True(
t,
strings.Contains(err.Error(), "insufficient"),
"Expected error about insufficient payment, got: %v",
err,
)
}
}
assert.Nil(t, msgs)
})
})
// Test 9 removed, retaining number for future use
// Test 10: Invalid signature on rendezvous
t.Run("invalid_signature_on_rendezvous", func(t *testing.T) {
runTestWithAllModes(t, "invalid_signature_on_rendezvous", func(t *testing.T, mode TestExecutionMode) {
// Create test dependencies
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks - SimpleVerify returns false for invalid signature
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(false)
// Set up compute mocks to handle the message processing
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
metadataTree := &tries.VectorCommitmentTree{}
// Set up the mock expectations for metadata
mockHG.On("GetVertex", [64]byte(metadataAddress)).Return(&mockVertex{}, nil)
mockHG.On("GetVertexData", [64]byte(metadataAddress)).Return(metadataTree, nil)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
msg, ce := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Set invalid signature
ce.ProofOfPayment[1] = []byte("invalid_signature")
// Process message should fail
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assert.Error(t, err)
assert.Nil(t, msgs)
})
})
// Test 11: Intrinsic token operation execution
t.Run("intrinsic_token_operation_execution", func(t *testing.T) {
runTestWithAllModes(t, "intrinsic_token_operation_execution", func(t *testing.T, mode TestExecutionMode) {
t.Skip("When multiphasic locking is added, support this")
})
})
// Test 12: Intrinsic hardcoded app execution
t.Run("intrinsic_hardcoded_app_execution", func(t *testing.T) {
runTestWithAllModes(t, "intrinsic_hardcoded_app_execution", func(t *testing.T, mode TestExecutionMode) {
// Create test dependencies
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: []byte{0x00, 0x01, 0x07, 0x01},
ExecutionContext: compute.ExecutionContextIntrinsic,
},
Identifier: []byte("intrinsic_op"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 13: Hypergraph context state mutation
t.Run("hypergraph_context_state_mutation", func(t *testing.T) {
runTestWithAllModes(t, "hypergraph_context_state_mutation", func(t *testing.T, mode TestExecutionMode) {
// Create test dependencies
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: hgstate.VertexAddsDiscriminator,
ExecutionContext: compute.ExecutionContextHypergraph,
},
Identifier: []byte("add_vertex"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 14: Extrinsic deployed code execution
t.Run("extrinsic_deployed_code_execution", func(t *testing.T) {
runTestWithAllModes(t, "extrinsic_deployed_code_execution", func(t *testing.T, mode TestExecutionMode) {
// Create test dependencies
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Perform deployment
domain := performDeployment(t, engine, mockHG, mockCompiler, engineMode)
// Set up mock for deployed code retrieval
// The test is using "deployed_code_addr" as the code address
code := &tries.VectorCommitmentTree{}
code.Insert([]byte{0}, []byte("circuit"), nil, big.NewInt(7))
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if the address ends with "deployed_code_addr"
codeAddrPart := string(bytes.TrimRight(addr[32:], "\x00"))
return codeAddrPart == "deployed_code_addr"
})).Return(code, nil)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("deployed_code_addr"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("execute_circuit"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 15: Conflict detection same address write
t.Run("conflict_detection_same_address_write", func(t *testing.T) {
runTestWithAllModes(t, "conflict_detection_same_address_write", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations that write to the same address (should be placed in different stages)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("same_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("same_app"), // Same address as op1
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 16: Conflict detection read write dependency
t.Run("conflict_detection_read_write_dependency", func(t *testing.T) {
runTestWithAllModes(t, "conflict_detection_read_write_dependency", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations with read-write dependency
// op1 reads from address A, op2 writes to address A
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("reader_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1_read"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("writer_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2_write"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 17: Conflict detection write write collision
t.Run("conflict_detection_write_write_collision", func(t *testing.T) {
runTestWithAllModes(t, "conflict_detection_write_write_collision", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Set up mocks for deployed code retrieval
// The test is using "state_writer1" and "state_writer2" as code addresses
code := &tries.VectorCommitmentTree{}
code.Insert([]byte{0}, []byte("circuit"), nil, big.NewInt(7))
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if the address ends with "state_writer1" or "state_writer2"
codeAddrPart := string(bytes.TrimRight(addr[32:], "\x00"))
return codeAddrPart == "state_writer1" || codeAddrPart == "state_writer2"
})).Return(code, nil)
// Create operations that both write to same state
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("state_writer1"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("writer1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("state_writer2"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("writer2"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 18: Conflict free parallel stage grouping
t.Run("conflict_free_parallel_stage_grouping", func(t *testing.T) {
runTestWithAllModes(t, "conflict_free_parallel_stage_grouping", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations that can run in parallel (no conflicts)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app1"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app2"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app3"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// All operations should be in the same stage since there are no conflicts
})
})
// Test 19: topological sort ordering
t.Run("topological_sort_ordering", func(t *testing.T) {
runTestWithAllModes(t, "topological_sort_ordering", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create complex DAG: op1 -> op2 -> op4, op1 -> op3 -> op4
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{[]byte("op1")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{[]byte("op1")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op4"),
Dependencies: [][]byte{[]byte("op2"), []byte("op3")},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// Should produce stages: [op1], [op2, op3], [op4]
})
})
// Test 20: Execution stage assignment correctness
t.Run("execution_stage_assignment_correctness", func(t *testing.T) {
runTestWithAllModes(t, "execution_stage_assignment_correctness", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations with mixed dependencies and conflicts
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_a"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_b"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_a"), // Conflict with op1
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_c"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op4"),
Dependencies: [][]byte{[]byte("op1"), []byte("op2")},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// Expected stages considering conflicts and dependencies:
// Stage 0: op1, op2 (no dependencies, no conflicts between them)
// Stage 1: op3 (conflicts with op1)
// Stage 2: op4 (depends on op1 and op2)
})
})
// Test 21: Materialize stores dependency structure
t.Run("materialize_stores_dependency_structure", func(t *testing.T) {
runTestWithAllModes(t, "materialize_stores_dependency_structure", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations with dependencies
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{[]byte("op1")},
},
}
msg, ce := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// Verify DAG structure is preserved in the materialized CodeExecute
assert.Equal(t, 2, len(ce.ExecuteOperations))
assert.Equal(t, []byte("op1"), ce.ExecuteOperations[0].Identifier)
assert.Equal(t, []byte("op2"), ce.ExecuteOperations[1].Identifier)
assert.Equal(t, [][]byte{[]byte("op1")}, ce.ExecuteOperations[1].Dependencies)
})
})
// Test 22: Materialize stores execution stages
t.Run("materialize_stores_execution_stages", func(t *testing.T) {
runTestWithAllModes(t, "materialize_stores_execution_stages", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations that will be in different stages
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app1"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app2"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app3"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{[]byte("op1"), []byte("op2")},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// The execution stages should be computed and stored
})
})
// Test 23: Materialize stores rendezvous
t.Run("materialize_stores_rendezvous", func(t *testing.T) {
runTestWithAllModes(t, "materialize_stores_rendezvous", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
msg, ce := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// Verify rendezvous is stored correctly
assert.NotNil(t, ce.Rendezvous)
})
})
// Test 24: Finalize collects all operation results
t.Run("finalize_collects_all_operation_results", func(t *testing.T) {
runTestWithAllModes(t, "finalize_collects_all_operation_results", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
// Set up compute metadata with proper keys
readKey := make([]byte, 57)
rand.Read(readKey)
writePub, writePriv, err := ed448.GenerateKey(rand.Reader)
writeKey := []byte(writePub)
domain := make([]byte, 32)
rand.Read(domain)
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Create mock execution results
results := []*compute.ExecutionResult{
{
OperationID: []byte("op1"),
Success: true,
Output: []byte("result1"),
},
{
OperationID: []byte("op2"),
Success: true,
Output: []byte("result2"),
},
}
var rendezvous [32]byte
rand.Read(rendezvous[:])
msg, _ := createTestCodeFinalizeMessage(t, domain, []byte(writePriv), &compute.ComputeIntrinsicConfiguration{ReadPublicKey: readKey, WritePublicKey: writeKey}, rendezvous, results, mockHG, mockKeyManager)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 25: Finalize commits durable state changes
t.Run("finalize_commits_durable_state_changes", func(t *testing.T) {
runTestWithAllModes(t, "finalize_commits_durable_state_changes", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up only the mocks needed for finalize operation
// Set up metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
rand.Read(readKey)
writePub, writePriv, err := ed448.GenerateKey(rand.Reader)
writeKey := []byte(writePub)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Add CommitRaw mock for app mode
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil).Maybe()
// Mock GetVertex for any address (needed for finalize operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add transaction mocks for commit operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil).Maybe()
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
// Mock the deployed code retrieval for finalize
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if it's trying to get deployed code
return bytes.HasPrefix(addr[:32], domain) &&
bytes.Equal(addr[32:48], bytes.Repeat([]byte{0x00}, 16))
})).Return([]byte("deployed_code"), nil)
// Create state transitions
results := []*compute.ExecutionResult{
{
OperationID: []byte("op1"),
Success: true,
Output: []byte("result1"),
},
}
var rendezvous [32]byte
rand.Read(rendezvous[:])
msg, _ := createTestCodeFinalizeMessage(t, domain, []byte(writePriv), &compute.ComputeIntrinsicConfiguration{ReadPublicKey: readKey, WritePublicKey: writeKey}, rendezvous, results, mockHG, mockKeyManager)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// For finalize operations in global mode, we expect no state changes
// since it's just acknowledging the finalization
// In app mode, state changes should be persisted
if mode != TestGlobalMode {
// In app mode, verify that state changes were persisted
// Since we can't easily verify the exact calls, we trust the test passes
}
})
})
// Test 26: Finalize rollback on operation failure
t.Run("finalize_rollback_on_operation_failure", func(t *testing.T) {
runTestWithAllModes(t, "finalize_rollback_on_operation_failure", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
rand.Read(readKey)
writePub, writePriv, err := ed448.GenerateKey(rand.Reader)
writeKey := []byte(writePub)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Add CommitRaw mock for app mode
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil).Maybe()
// Mock GetVertex for any address (needed for finalize operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add transaction mocks for commit operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil).Maybe()
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
// Mock the deployed code retrieval for finalize
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if it's trying to get deployed code
return bytes.HasPrefix(addr[:32], domain) &&
bytes.Equal(addr[32:48], bytes.Repeat([]byte{0x00}, 16))
})).Return([]byte("deployed_code"), nil)
// Create results with failure
results := []*compute.ExecutionResult{
{
OperationID: []byte("op1"),
Success: false,
Error: []byte("execution failed"),
},
}
var rendezvous [32]byte
rand.Read(rendezvous[:])
msg, _ := createTestCodeFinalizeMessage(t, domain, []byte(writePriv), &compute.ComputeIntrinsicConfiguration{ReadPublicKey: readKey, WritePublicKey: writeKey}, rendezvous, results, mockHG, mockKeyManager)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
// State changes should not be committed for failed operations
})
})
// Test 27: Finalize dispatch message output only
t.Run("finalize_dispatch_message_output_only", func(t *testing.T) {
runTestWithAllModes(t, "finalize_dispatch_message_output_only", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
rand.Read(readKey)
writePub, writePriv, err := ed448.GenerateKey(rand.Reader)
writeKey := []byte(writePub)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Add CommitRaw mock for app mode
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil).Maybe()
// Mock GetVertex for any address (needed for finalize operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add transaction mocks for commit operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil).Maybe()
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
// Mock the deployed code retrieval for finalize
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if it's trying to get deployed code
return bytes.HasPrefix(addr[:32], domain) &&
bytes.Equal(addr[32:48], bytes.Repeat([]byte{0x00}, 16))
})).Return([]byte("deployed_code"), nil)
// Create results with message output
results := []*compute.ExecutionResult{
{
OperationID: []byte("op1"),
Success: true,
Output: []byte("transient_output"),
},
}
var rendezvous [32]byte
rand.Read(rendezvous[:])
// Create finalize with message output
cf := compute.NewCodeFinalize(
rendezvous,
[32]byte(domain),
results,
[]*compute.StateTransition{}, // No state transitions
[]byte("message_output_only"),
[]byte(writePriv),
&compute.ComputeIntrinsicConfiguration{
ReadPublicKey: readKey,
WritePublicKey: writeKey,
},
nil, nil, nil, nil, nil, nil,
)
// Wrap in MessageRequest and serialize
finalizeReq := &protobufs.MessageRequest{
Request: &protobufs.MessageRequest_CodeFinalize{
CodeFinalize: cf.ToProtobuf(),
},
}
outFees := []*big.Int{big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
bundle := &protobufs.MessageBundle{
Requests: []*protobufs.MessageRequest{
payment,
finalizeReq,
},
}
bundleBytes, err := bundle.ToCanonicalBytes()
require.NoError(t, err)
// Create message
hash := sha3.Sum256(bundleBytes)
require.NoError(t, err)
msg := &protobufs.Message{
Address: domain,
Hash: hash[:],
Payload: bundleBytes,
}
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 28: Finalize partial success handling
t.Run("finalize_partial_success_handling", func(t *testing.T) {
runTestWithAllModes(t, "finalize_partial_success_handling", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
rand.Read(readKey)
writePub, writePriv, err := ed448.GenerateKey(rand.Reader)
writeKey := []byte(writePub)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Add CommitRaw mock for app mode
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil).Maybe()
// Mock GetVertex for any address (needed for finalize operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add transaction mocks for commit operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil).Maybe()
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
// Mock the deployed code retrieval for finalize
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if it's trying to get deployed code
return bytes.HasPrefix(addr[:32], domain) &&
bytes.Equal(addr[32:48], bytes.Repeat([]byte{0x00}, 16))
})).Return([]byte("deployed_code"), nil)
// Create mixed results - some succeed, some fail
results := []*compute.ExecutionResult{
{
OperationID: []byte("op1"),
Success: true,
Output: []byte("result1"),
},
{
OperationID: []byte("op2"),
Success: false,
Error: []byte("op2 failed"),
},
{
OperationID: []byte("op3"),
Success: true,
Output: []byte("result3"),
},
}
var rendezvous [32]byte
rand.Read(rendezvous[:])
msg, _ := createTestCodeFinalizeMessage(t, domain, []byte(writePriv), &compute.ComputeIntrinsicConfiguration{ReadPublicKey: readKey, WritePublicKey: writeKey}, rendezvous, results, mockHG, mockKeyManager)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 29: Empty operations list rejected
t.Run("empty_operations_list_rejected", func(t *testing.T) {
runTestWithAllModes(t, "empty_operations_list_rejected", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Add CommitRaw mock for app mode
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil).Maybe()
// Mock GetVertex for any address (needed for finalize operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add transaction mocks for commit operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil).Maybe()
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
// Add NewMultiproof mock
mockMultiproof := &mocks.MockMultiproof{}
mockMultiproof.On("FromBytes", mock.Anything).Return(nil).Maybe()
mockInclusionProver.On("NewMultiproof").Return(mockMultiproof).Maybe()
// Set up mocks
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
// Create message with empty operations list
ops := []*compute.ExecuteOperation{}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message should fail
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assert.Error(t, err)
assert.Nil(t, msgs)
// In global mode, CodeExecute messages are not allowed after deployment
// In app mode, we should get the empty operations error
if mode == TestGlobalMode {
assert.Contains(t, err.Error(), "non-deploy messages not allowed in global mode")
} else {
assert.Contains(t, err.Error(), "empty")
}
})
})
// Test 30: Max operations limit enforcement
t.Run("max_operations_limit_enforcement", func(t *testing.T) {
runTestWithAllModes(t, "max_operations_limit_enforcement", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
domain := make([]byte, 32)
rand.Read(domain)
// For app mode, set up compute metadata so the intrinsic can be loaded
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Add CommitRaw mock for app mode
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil).Maybe()
// Mock GetVertex for any address (needed for finalize operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add transaction mocks for commit operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil).Maybe()
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
// Add NewMultiproof mock
mockMultiproof := &mocks.MockMultiproof{}
mockMultiproof.On("FromBytes", mock.Anything).Return(nil).Maybe()
mockInclusionProver.On("NewMultiproof").Return(mockMultiproof).Maybe()
// Mock GetVertexData for deployed code addresses (returns empty tree)
mockHG.On("GetVertexData", mock.Anything).Return(&tries.VectorCommitmentTree{}, nil).Maybe()
// Set up mocks
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
// Create more operations than allowed limit (assuming limit is 100)
ops := make([]*compute.ExecuteOperation, 101)
for i := 0; i < 101; i++ {
ops[i] = &compute.ExecuteOperation{
Application: compute.Application{
Address: makeExtrinsicAddress(fmt.Sprintf("app%d", i)),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte(fmt.Sprintf("op%d", i)),
Dependencies: [][]byte{},
}
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message should fail
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assert.Error(t, err)
assert.Nil(t, msgs)
// In global mode, CodeExecute messages are not allowed after deployment
// In app mode, we should get the limit error
if mode == TestGlobalMode {
assert.Contains(t, err.Error(), "non-deploy messages not allowed in global mode")
} else {
assert.Contains(t, err.Error(), "limit")
}
})
})
// Test 31: dynamic fee enforcement
t.Run("dynamic_fee_enforcement", func(t *testing.T) {
runTestWithAllModes(t, "dynamic_fee_enforcement", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockKeyManager.On("ValidateSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
rand.Read(readKey)
writePub, writePriv, err := ed448.GenerateKey(rand.Reader)
writeKey := []byte(writePub)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Additional mocks specific to this test
mockHG.On("Get", mock.Anything, mock.Anything, mock.Anything).Return([]byte("old_value"), nil)
mockHG.On("Set", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// Mock GetVertex for any address (needed for finalize operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add transaction mocks for commit operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil)
mockHG.On("GetProver").Return(mockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
results := []*compute.ExecutionResult{
{
OperationID: []byte("op1"),
Success: true,
Output: []byte("result1"),
},
{
OperationID: []byte("op2"),
Success: true,
Output: []byte("result2"),
},
}
var rendezvous [32]byte
rand.Read(rendezvous[:])
msg, cf := createTestCodeFinalizeMessage(t, domain, []byte(writePriv), &compute.ComputeIntrinsicConfiguration{ReadPublicKey: readKey, WritePublicKey: writeKey}, rendezvous, results, mockHG, mockKeyManager)
// Process message
state := hgstate.NewHypergraphState(mockHG)
// Dynamic fee too high
msgs, err := engine.ProcessMessage(1, big.NewInt(10000000), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, true)
assert.Len(t, cf.Results, 2)
})
})
// Test 32: Multiple execution contexts
t.Run("multiple_execution_contexts", func(t *testing.T) {
runTestWithAllModes(t, "multiple_execution_contexts", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
// Perform deployment with the same keys
domain := performDeploymentWithKeys(t, engine, mockHG, mockCompiler, readKey, writeKey, engineMode)
// Set up compute metadata
setupComputeMetadata(t, mockHG, domain, readKey, writeKey)
// Create operations with different execution contexts
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: []byte{0x00, 0x01, 0x06, 0x01},
ExecutionContext: compute.ExecutionContextIntrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: hgstate.VertexAddsDiscriminator,
ExecutionContext: compute.ExecutionContextHypergraph,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{[]byte("op1")},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("extrinsic_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3"),
Dependencies: [][]byte{[]byte("op2")},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 33: Code not deployed execution fails
t.Run("code_not_deployed_execution_fails", func(t *testing.T) {
runTestWithAllModes(t, "code_not_deployed_execution_fails", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Set up mocks - no deployment performed
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
mockHG.On("GetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("code not found"))
// Mock GetVertex for any address (needed for code execution operations)
mockHG.On("GetVertex", mock.Anything).Return(nil, store.ErrNotFound).Maybe()
// Add mocks for app mode
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil).Maybe()
mockMultiproof := &mocks.MockMultiproof{}
mockMultiproof.On("FromBytes", mock.Anything).Return(nil).Maybe()
mockInclusionProver.On("NewMultiproof").Return(mockMultiproof, nil).Maybe()
// Add transaction mocks for verify operation
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil).Maybe()
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
// Create operation referencing non-deployed code
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("non_deployed_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message should fail
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assert.Error(t, err)
// Different error messages in different modes
if engineMode == engines.GlobalMode {
assert.Contains(t, err.Error(), "non-deploy messages not allowed in global mode")
} else {
assert.Contains(t, err.Error(), "not found")
}
assert.Nil(t, msgs)
})
})
// Test 34: Input types validation from deployment
t.Run("input_types_validation_from_deployment", func(t *testing.T) {
runTestWithAllModes(t, "input_types_validation_from_deployment", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Set up mocks
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil)
mockHG.On("GetProver").Return(mockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockMultiproof := &mocks.MockMultiproof{}
mockMultiproof.On("FromBytes", mock.Anything).Return(nil).Maybe()
mockInclusionProver.On("NewMultiproof").Return(mockMultiproof, nil).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil)
mockHG.On("GetVertex", mock.Anything).Return(&mockVertex{}, nil)
// Set up mock for deployed code retrieval
// The test is using "typed_app" as the code address
code := &tries.VectorCommitmentTree{}
code.Insert([]byte{0}, []byte("circuit"), nil, big.NewInt(7))
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if the address ends with "typed_app"
codeAddrPart := string(bytes.TrimRight(addr[32:], "\x00"))
return codeAddrPart == "typed_app"
})).Return(code, nil)
mockHG.On("GetVertexData", mock.Anything).Return(&tries.VectorCommitmentTree{}, nil)
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
// Perform deployment with specific input types
performDeployment(t, engine, mockHG, mockCompiler, engineMode)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("typed_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 35: Output types validation from deployment
t.Run("output_types_validation_from_deployment", func(t *testing.T) {
runTestWithAllModes(t, "output_types_validation_from_deployment", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up compute metadata with test keys (Ed448 keys are 57 bytes)
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Set up mocks
txn := &mockTransaction{}
mockHG.On("NewTransaction", false).Return(txn, nil)
mockHG.On("GetProver").Return(mockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockMultiproof := &mocks.MockMultiproof{}
mockMultiproof.On("FromBytes", mock.Anything).Return(nil).Maybe()
mockInclusionProver.On("NewMultiproof").Return(mockMultiproof, nil).Maybe()
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil)
mockHG.On("GetVertex", mock.Anything).Return(&mockVertex{}, nil)
// Set up mock for deployed code retrieval
// The test is using "typed_output_app" as the code address
code := &tries.VectorCommitmentTree{}
code.Insert([]byte{0}, []byte("circuit"), nil, big.NewInt(7))
mockHG.On("GetVertexData", mock.MatchedBy(func(addr [64]byte) bool {
// Check if the address ends with "typed_output_app"
codeAddrPart := string(bytes.TrimRight(addr[32:], "\x00"))
return codeAddrPart == "typed_output_app"
})).Return(code, nil)
mockHG.On("GetVertexData", mock.Anything).Return(&tries.VectorCommitmentTree{}, nil)
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
mockBulletproofProver.On("SimpleVerify", mock.Anything, mock.Anything, mock.Anything).Return(true)
// Perform deployment with specific output types
performDeployment(t, engine, mockHG, mockCompiler, engineMode)
ops := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("typed_output_app"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
}
msg, _ := createTestCodeExecuteMessage(t, mockHG, domain, ops)
// Process message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), msg.Address, msg.Payload, state)
assertCodeExecutionResult(t, mode, msgs, err, false)
})
})
// Test 23: Bundled messages support multiple operations atomically
t.Run("bundled_messages_atomic_operations", func(t *testing.T) {
runTestWithAllModes(t, "bundled_messages_atomic_operations", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
`
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Create operations for bundling
operations := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_a"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1"),
Dependencies: [][]byte{},
},
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_b"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2"),
Dependencies: [][]byte{},
},
}
// Create a bundled message that includes both deployment and execution
bundledMsg := createDeployAndExecuteBundle(t, mockHG, readKey, writeKey, operations)
// Process the bundled message - this should work even in Global mode
// because the bundle contains both deployment and execution atomically
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), bundledMsg.Address, bundledMsg.Payload, state)
// In global mode, this should fail because bundles bypass the
// single-operation restriction, except when not including a deploy
if engineMode == engines.GlobalMode {
assert.Error(t, err, "Non-deploy bundled messages should not work in GlobalMode")
assert.Nil(t, msgs, "Should not get responses from bundled operations")
} else {
assertCodeExecutionResult(t, mode, msgs, err, false)
}
})
})
// Test 24: Multiple bundled operations processed sequentially
t.Run("bundled_multiple_operations_sequential", func(t *testing.T) {
runTestWithAllModes(t, "bundled_multiple_operations_sequential", func(t *testing.T, mode TestExecutionMode) {
logger := zap.NewNop()
mockInclusionProver := new(mocks.MockInclusionProver)
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
mockHG := tests.CreateHypergraphWithInclusionProver(mockInclusionProver)
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{}).Maybe()
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
mockHG.On("GetCoveredPrefix").Return([]int{}, nil)
mockKeyManager := new(mocks.MockKeyManager)
mockBulletproofProver := new(mocks.MockBulletproofProver)
mockVerEnc := new(mocks.MockVerifiableEncryptor)
mockDecaf := new(mocks.MockDecafConstructor)
mockCompiler := new(mocks.MockCompiler)
// Map test mode to actual engine mode
var engineMode engines.ExecutionMode
switch mode {
case TestGlobalMode:
engineMode = engines.GlobalMode
case TestApplicationMode:
engineMode = engines.ApplicationMode
case TestMixedMode:
engineMode = engines.ApplicationMode
}
engine, err := engines.NewComputeExecutionEngine(
logger,
mockHG,
mockKeyManager,
mockInclusionProver,
mockBulletproofProver,
mockVerEnc,
mockDecaf,
mockCompiler,
engineMode,
)
require.NoError(t, err)
// Set up mocks
setupComputeMocks(t, mockHG, mockInclusionProver, mockBulletproofProver, engineMode)
setupTokenIntrinsicMocks(t, mockHG)
// Generate keys for metadata
readKey := make([]byte, 57)
writeKey := make([]byte, 57)
rand.Read(readKey)
rand.Read(writeKey)
domain := make([]byte, 32)
rand.Read(domain)
// Set up compute metadata
metadataAddress := slices.Concat(domain, bytes.Repeat([]byte{0xff}, 32))
rdfSchema := `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.
` // Valid RDF schema for test
err = tests.SetHypergraphComputeMetadataData(
mockHG,
metadataAddress,
rdfSchema,
nil, // creator not needed for test
readKey,
writeKey,
)
require.NoError(t, err)
// Create multiple operation sets
ops1 := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_1"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op1_a"),
Dependencies: [][]byte{},
},
}
ops2 := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_2"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op2_a"),
Dependencies: [][]byte{},
},
}
ops3 := []*compute.ExecuteOperation{
{
Application: compute.Application{
Address: makeExtrinsicAddress("app_3"),
ExecutionContext: compute.ExecutionContextExtrinsic,
},
Identifier: []byte("op3_a"),
Dependencies: [][]byte{},
},
}
// Create a bundle with multiple operation sets
bundledMsg := createMultiOperationBundle(t, mockHG, domain, ops1, ops2, ops3)
// Process the bundled message
state := hgstate.NewHypergraphState(mockHG)
msgs, err := engine.ProcessMessage(1, big.NewInt(0), bundledMsg.Address, bundledMsg.Payload, state)
// Verify that all operations were processed
if engineMode == engines.GlobalMode {
// In global mode, this will fail due to deployment requirements
// but it demonstrates the bundling concept
if err == nil {
t.Logf("Global mode result: error=%v, responses=%d", err, len(msgs.Messages))
} else {
t.Logf("Global mode result: error=%v", err)
}
} else {
// In application mode, verify sequential processing
if err == nil {
assert.NotNil(t, msgs)
}
}
})
})
}
// createBundledMessage creates a message containing multiple bundled operations
func createBundledMessage(t *testing.T, domain []byte, operations ...*protobufs.MessageRequest) *protobufs.Message {
bundle := &protobufs.MessageBundle{
Requests: operations,
}
// Serialize the bundle
bundleBytes, err := bundle.ToCanonicalBytes()
require.NoError(t, err)
// Create the message
hash := sha3.Sum256(bundleBytes)
require.NoError(t, err)
return &protobufs.Message{
Address: domain,
Hash: hash[:],
Payload: bundleBytes,
}
}
// createDeployAndExecuteBundle creates a bundle with deployment and execution operations
func createDeployAndExecuteBundle(t *testing.T, mockHg *mocks.MockHypergraph, readKey, writeKey []byte, operations []*compute.ExecuteOperation) *protobufs.Message {
// Create deployment payload
deployArgs := &protobufs.ComputeDeploy{
Config: &protobufs.ComputeConfiguration{
ReadPublicKey: readKey,
WritePublicKey: writeKey,
},
RdfSchema: []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/>
qcl:Application a rdfs:Class.
qcl:address a rdfs:Property;
rdfs:domain qcl:ByteArray;
qcl:size 64;
qcl:order 0;
rdfs:range qcl:Application.
qcl:computationSchema a rdfs:Property;
rdfs:domain qcl:String;
qcl:size 1024;
qcl:order 1;
rdfs:range qcl:Application.
qcl:permittedContracts a rdfs:Property;
rdfs:domain qcl:ByteArray;
qcl:size 64;
qcl:order 2;
rdfs:range qcl:Application.`),
}
// Create code execute payload
var domain [32]byte
rand.Read(domain[:])
var rendezvous [32]byte
rand.Read(rendezvous[:])
// Create valid payment transaction bytes
outFees := []*big.Int{big.NewInt(1), big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHg,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000002)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
paymentBytes, err := payment.GetPendingTransaction().ToCanonicalBytes()
ce := compute.NewCodeExecute(
domain,
paymentBytes,
[]byte("mock_secret"),
rendezvous,
operations,
nil, nil, nil, nil, nil, nil,
)
// Manually set up proof of payment (like createTestCodeExecuteMessage does)
ce.ProofOfPayment[0] = paymentBytes
ce.ProofOfPayment[1] = make([]byte, 112) // Schnorr signature size
rand.Read(ce.ProofOfPayment[1])
// Create bundled message
return createBundledMessage(t, domain[:], payment, &protobufs.MessageRequest{Request: &protobufs.MessageRequest_ComputeDeploy{ComputeDeploy: deployArgs}}, &protobufs.MessageRequest{Request: &protobufs.MessageRequest_CodeExecute{CodeExecute: ce.ToProtobuf()}})
}
// createCompleteBundleWithPayment creates a bundle with payment, intrinsic deploy, code deploy, and execution
func createCompleteBundleWithPayment(
t *testing.T,
mockHG *mocks.MockHypergraph,
domain []byte,
readKey, writeKey []byte,
sourceCode []byte,
mockCompiler *mocks.MockCompiler,
operations []*compute.ExecuteOperation,
) *protobufs.Message {
payloads := []*protobufs.MessageRequest{}
outFees := []*big.Int{big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
paymentBytes, err := payment.GetPendingTransaction().ToCanonicalBytes()
payloads = append(payloads, payment)
// Create intrinsic deployment payload
deployArgs := &protobufs.ComputeDeploy{
Config: &protobufs.ComputeConfiguration{
ReadPublicKey: readKey,
WritePublicKey: writeKey,
},
RdfSchema: []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.
`),
}
payloads = append(payloads, &protobufs.MessageRequest{Request: &protobufs.MessageRequest_ComputeDeploy{ComputeDeploy: deployArgs}})
// Create code deployment payload (if source code provided)
if sourceCode != nil {
deployment, err := compute.NewCodeDeployment(
[32]byte(domain),
sourceCode,
[2]string{"qcl:Int", "qcl:Int"},
[2][]int{{4}, {4}},
[]string{"qcl:Int"},
mockCompiler,
)
require.NoError(t, err)
err = deployment.Prove(1)
require.NoError(t, err)
payloads = append(payloads, &protobufs.MessageRequest{Request: &protobufs.MessageRequest_CodeDeploy{CodeDeploy: deployment.ToProtobuf()}})
}
// Create code execution payload (if operations provided)
if operations != nil && len(operations) > 0 {
var domain [32]byte
rand.Read(domain[:])
var rendezvous [32]byte
rand.Read(rendezvous[:])
// Manually set up proof of payment (like createTestCodeExecuteMessage does)
proofOfPayment := [2][]byte{}
proofOfPayment[0] = paymentBytes
proofOfPayment[1] = make([]byte, 112) // Schnorr signature size
rand.Read(proofOfPayment[1])
ce := &compute.CodeExecute{
Domain: domain,
Rendezvous: rendezvous,
ProofOfPayment: proofOfPayment,
ExecuteOperations: operations,
}
payloads = append(payloads, &protobufs.MessageRequest{Request: &protobufs.MessageRequest_CodeExecute{CodeExecute: ce.ToProtobuf()}})
}
// Create bundled message
return createBundledMessage(t, compute.COMPUTE_INTRINSIC_DOMAIN[:], payloads...)
}
// createMultiOperationBundle creates a bundle with multiple code execution operations
func createMultiOperationBundle(t *testing.T, mockHG *mocks.MockHypergraph, domain []byte, operations ...[]*compute.ExecuteOperation) *protobufs.Message {
payloads := []*protobufs.MessageRequest{}
outFees := []*big.Int{big.NewInt(1)}
total := big.NewInt(10000000)
outFees = append(outFees, total)
payment, err := tests.CreateValidQUILPendingTransactionPayload(
mockHG,
1,
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[][]byte{make([]byte, 56)},
[]*big.Int{big.NewInt(10000001)},
[]*big.Int{big.NewInt(0)},
outFees,
0,
)
if err != nil {
panic(err)
}
paymentBytes, err := payment.GetPendingTransaction().ToCanonicalBytes()
for _, ops := range operations {
var rendezvous [32]byte
rand.Read(rendezvous[:])
ce := compute.NewCodeExecute(
[32]byte(domain),
paymentBytes,
[]byte("mock_secret"),
rendezvous,
ops,
nil, nil, nil, nil, nil, nil,
)
// Manually set up proof of payment (like createTestCodeExecuteMessage does)
ce.ProofOfPayment[0] = paymentBytes
ce.ProofOfPayment[1] = make([]byte, 112) // Schnorr signature size
rand.Read(ce.ProofOfPayment[1])
payloads = append(payloads, payment, &protobufs.MessageRequest{Request: &protobufs.MessageRequest_CodeExecute{CodeExecute: ce.ToProtobuf()}})
}
return createBundledMessage(t, domain[:], payloads...)
}
var _ hypergraph.Vertex = (*mockVertex)(nil)