mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
740 lines
26 KiB
Go
740 lines
26 KiB
Go
package engines_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"math/big"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
"golang.org/x/crypto/sha3"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/engines"
|
|
"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/tests"
|
|
"source.quilibrium.com/quilibrium/monorepo/protobufs"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/crypto"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/mocks"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/schema"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/tries"
|
|
)
|
|
|
|
func newTokenRDFHypergraphSchema(
|
|
appAddress []byte,
|
|
config *token.TokenIntrinsicConfiguration,
|
|
) (string, error) {
|
|
schemaDoc, err := token.PrepareRDFSchemaFromConfig(appAddress, config)
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "new token rdf hypergraph schema")
|
|
}
|
|
|
|
valid, err := (&schema.TurtleRDFParser{}).Validate(schemaDoc)
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "new token rdf hypergraph schema")
|
|
}
|
|
|
|
if !valid {
|
|
return "", errors.Wrap(
|
|
errors.New("invalid schema"),
|
|
"new token rdf hypergraph schema",
|
|
)
|
|
}
|
|
|
|
return schemaDoc, nil
|
|
}
|
|
|
|
// Creates a mintable token configuration with authority for testing
|
|
func createMintableTestConfig() *token.TokenIntrinsicConfiguration {
|
|
return &token.TokenIntrinsicConfiguration{
|
|
Name: "Test Token",
|
|
Symbol: "TEST",
|
|
Supply: big.NewInt(100000),
|
|
Units: big.NewInt(10),
|
|
Behavior: token.Acceptable | token.Divisible,
|
|
}
|
|
}
|
|
|
|
func TestTokenExecutionEngine_Start(t *testing.T) {
|
|
logger := zap.NewNop()
|
|
mockHG := new(mocks.MockHypergraph)
|
|
mockHG.On("GetCoveredPrefix").Return([]int{}, nil).Maybe()
|
|
mockClockStore := new(mocks.MockClockStore)
|
|
mockKeyManager := new(mocks.MockKeyManager)
|
|
mockInclusionProver := new(mocks.MockInclusionProver)
|
|
mockBulletproofProver := new(mocks.MockBulletproofProver)
|
|
mockVerEnc := new(mocks.MockVerifiableEncryptor)
|
|
mockDecaf := new(mocks.MockDecafConstructor)
|
|
|
|
engine, err := engines.NewTokenExecutionEngine(
|
|
logger,
|
|
mockHG,
|
|
mockClockStore,
|
|
mockKeyManager,
|
|
mockInclusionProver,
|
|
mockBulletproofProver,
|
|
mockVerEnc,
|
|
mockDecaf,
|
|
engines.ApplicationMode,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// Test starting and stopping the engine
|
|
errChan := engine.Start()
|
|
|
|
// Engine should start without errors
|
|
select {
|
|
case err := <-errChan:
|
|
t.Fatalf("unexpected error from Start: %v", err)
|
|
default:
|
|
// Expected: no immediate error
|
|
}
|
|
|
|
// Stop the engine
|
|
<-engine.Stop(false)
|
|
}
|
|
|
|
func TestTokenExecutionEngine_ProcessMessage_DeployEdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
mode engines.ExecutionMode
|
|
setupMocks func(*mocks.MockHypergraph, *mocks.MockKeyManager, *mocks.MockVerifiableEncryptor, *mocks.MockDecafConstructor, *mocks.MockBulletproofProver, *mocks.MockInclusionProver)
|
|
message *protobufs.Message
|
|
address []byte
|
|
wantErr bool
|
|
errContains string
|
|
}{
|
|
{
|
|
name: "nil_message",
|
|
mode: engines.ApplicationMode,
|
|
setupMocks: func(mockHG *mocks.MockHypergraph, mockKM *mocks.MockKeyManager, mockVE *mocks.MockVerifiableEncryptor, mockDC *mocks.MockDecafConstructor, mockBP *mocks.MockBulletproofProver, mockIP *mocks.MockInclusionProver) {
|
|
// No mocks needed
|
|
},
|
|
message: &protobufs.Message{},
|
|
address: token.TOKEN_BASE_DOMAIN[:], // Use 32-byte address
|
|
wantErr: true,
|
|
errContains: "invalid message",
|
|
},
|
|
{
|
|
name: "message_payload_too_short",
|
|
mode: engines.ApplicationMode,
|
|
setupMocks: func(mockHG *mocks.MockHypergraph, mockKM *mocks.MockKeyManager, mockVE *mocks.MockVerifiableEncryptor, mockDC *mocks.MockDecafConstructor, mockBP *mocks.MockBulletproofProver, mockIP *mocks.MockInclusionProver) {
|
|
// No mocks needed
|
|
},
|
|
message: &protobufs.Message{
|
|
Payload: []byte{0x01}, // Less than 4 bytes
|
|
},
|
|
address: token.TOKEN_BASE_DOMAIN[:], // Use 32-byte address
|
|
wantErr: true,
|
|
errContains: "invalid message",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
logger := zap.NewNop()
|
|
mockHG := new(mocks.MockHypergraph)
|
|
mockHG.On("GetCoveredPrefix").Return([]int{}, nil).Maybe()
|
|
mockClockStore := new(mocks.MockClockStore)
|
|
mockKeyManager := new(mocks.MockKeyManager)
|
|
mockInclusionProver := new(mocks.MockInclusionProver)
|
|
mockBulletproofProver := new(mocks.MockBulletproofProver)
|
|
mockVerEnc := new(mocks.MockVerifiableEncryptor)
|
|
mockDecaf := new(mocks.MockDecafConstructor)
|
|
|
|
tt.setupMocks(mockHG, mockKeyManager, mockVerEnc, mockDecaf, mockBulletproofProver, mockInclusionProver)
|
|
|
|
engine, err := engines.NewTokenExecutionEngine(
|
|
logger,
|
|
mockHG,
|
|
mockClockStore,
|
|
mockKeyManager,
|
|
mockInclusionProver,
|
|
mockBulletproofProver,
|
|
mockVerEnc,
|
|
mockDecaf,
|
|
tt.mode,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// Process message
|
|
state := hgstate.NewHypergraphState(mockHG)
|
|
responses, err := engine.ProcessMessage(1, big.NewInt(1), tt.address, tt.message.Payload, state)
|
|
|
|
if tt.wantErr {
|
|
assert.Error(t, err)
|
|
if tt.errContains != "" {
|
|
assert.Contains(t, err.Error(), tt.errContains)
|
|
}
|
|
assert.Nil(t, responses)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, responses)
|
|
err = responses.State.Commit()
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTokenExecutionEngine_BundledMessages(t *testing.T) {
|
|
t.Skip("something weird about payment setup")
|
|
logger := zap.NewNop()
|
|
mockHG := new(mocks.MockHypergraph)
|
|
mockHG.On("GetCoveredPrefix").Return([]int{}, nil).Maybe()
|
|
mockClockStore := new(mocks.MockClockStore)
|
|
mockKeyManager := new(mocks.MockKeyManager)
|
|
mockInclusionProver := new(mocks.MockInclusionProver)
|
|
mockBulletproofProver := new(mocks.MockBulletproofProver)
|
|
mockVerEnc := new(mocks.MockVerifiableEncryptor)
|
|
mockDecaf := new(mocks.MockDecafConstructor)
|
|
|
|
// Mock GetProver - required for hypergraph state initialization
|
|
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
|
|
|
|
// Mock inclusion prover for CommitRaw operations
|
|
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 64), nil).Maybe()
|
|
|
|
// Mock transaction operations
|
|
mockTxn := &mockTransaction{}
|
|
mockHG.On("NewTransaction", mock.Anything).Return(mockTxn, nil).Maybe()
|
|
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
|
|
// Mock for TrackChange
|
|
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
|
|
// Mock commit - should return [][]byte
|
|
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{tries.ShardKey{L1: [3]byte{}, L2: [32]byte{}}: [][]byte{make([]byte, 74), make([]byte, 74), make([]byte, 74), make([]byte, 74)}}).Maybe()
|
|
|
|
// Set up the mock to return not found for token transactions (LoadTokenIntrinsic)
|
|
mockHG.On("GetVertex", [64]byte{0xb, 0x8d, 0xa5, 0x37, 0xba, 0x80, 0x77, 0x1, 0x23, 0x9, 0xc6, 0x53, 0x32, 0xd2, 0xbb, 0x4b, 0x6c, 0xc6, 0x8e, 0x6e, 0x61, 0x60, 0xbd, 0xa, 0xa1, 0x98, 0xe8, 0x7f, 0xa8, 0x1c, 0x65, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}).Return(nil, errors.New("not found")).Maybe()
|
|
|
|
// Mock for deployment
|
|
mockKeyManager.On("Prove", mock.Anything, mock.Anything, mock.Anything).Return([]byte("signature"), nil).Maybe()
|
|
mockBulletproofProver.On("GenerateRangeProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte("proof"), nil).Maybe()
|
|
mockBulletproofProver.On("ProveCreate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte("proof"), nil).Maybe()
|
|
mockBulletproofProver.On("VerifyHidden", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true)
|
|
mockBulletproofProver.On("VerifyRangeProof", mock.Anything, mock.Anything, mock.Anything).Return(true)
|
|
mockBulletproofProver.On("SumCheck", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true)
|
|
mockVerEnc.On("GenerateKeyPair").Return(make([]byte, 57), make([]byte, 57), nil).Maybe()
|
|
|
|
engine, err := engines.NewTokenExecutionEngine(
|
|
logger,
|
|
mockHG,
|
|
mockClockStore,
|
|
mockKeyManager,
|
|
mockInclusionProver,
|
|
mockBulletproofProver,
|
|
mockVerEnc,
|
|
mockDecaf,
|
|
engines.ApplicationMode,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// Create a bundle with just deploy and a payment
|
|
// We'll test vertex operations separately since they need the deployed address
|
|
tokenDeploy := createTokenDeployPayloadFull(t, mockHG)
|
|
require.NoError(t, err)
|
|
|
|
bundleBytes, err := tokenDeploy.ToCanonicalBytes()
|
|
require.NoError(t, err)
|
|
|
|
// Create bundle message
|
|
bundleMsg := &protobufs.Message{
|
|
Address: token.TOKEN_BASE_DOMAIN[:],
|
|
Payload: bundleBytes,
|
|
}
|
|
|
|
// Set hash
|
|
hash := sha3.Sum256(bundleMsg.Payload)
|
|
bundleMsg.Hash = hash[:]
|
|
|
|
// Process bundle
|
|
state := hgstate.NewHypergraphState(mockHG)
|
|
responses, err := engine.ProcessMessage(1, big.NewInt(1), token.TOKEN_BASE_DOMAIN[:], bundleMsg.Payload, state)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, responses)
|
|
err = responses.State.Commit()
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestTokenExecutionEngine_ModeSwitch(t *testing.T) {
|
|
// Test that GlobalMode properly restricts operations after deployment
|
|
logger := zap.NewNop()
|
|
mockHG := new(mocks.MockHypergraph)
|
|
mockHG.On("GetCoveredPrefix").Return([]int{}, nil).Maybe()
|
|
mockClockStore := new(mocks.MockClockStore)
|
|
mockKeyManager := new(mocks.MockKeyManager)
|
|
mockInclusionProver := new(mocks.MockInclusionProver)
|
|
mockBulletproofProver := new(mocks.MockBulletproofProver)
|
|
mockVerEnc := new(mocks.MockVerifiableEncryptor)
|
|
mockDecaf := new(mocks.MockDecafConstructor)
|
|
|
|
// Create test address
|
|
testAddr := make([]byte, 32)
|
|
rand.Read(testAddr)
|
|
vertexAddr := [64]byte(slices.Concat(testAddr, bytes.Repeat([]byte{0xff}, 32)))
|
|
|
|
// First, test that we can deploy in global mode
|
|
mockHG.On("GetVertex", mock.Anything).Return(nil, errors.New("not found")).Maybe()
|
|
|
|
// Mock GetProver - required for hypergraph state initialization
|
|
mockHG.On("GetProver").Return(mockInclusionProver).Maybe()
|
|
|
|
// Mock inclusion prover for CommitRaw operations
|
|
mockInclusionProver.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 64), nil).Maybe()
|
|
|
|
// Mock transaction operations
|
|
mockTxn := &mockTransaction{}
|
|
mockHG.On("NewTransaction", mock.Anything).Return(mockTxn, nil).Maybe()
|
|
mockHG.On("AddVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
mockHG.On("SetVertexData", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
mockHG.On("GetShardCommits", mock.Anything, mock.Anything).Return([][]byte{make([]byte, 64), make([]byte, 64), make([]byte, 64), make([]byte, 64)}, nil)
|
|
|
|
// Mock for TrackChange
|
|
mockHG.On("TrackChange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
|
|
mockHG.On("GetMetadata", mock.Anything).Return(nil, errors.New("not found")).Maybe()
|
|
mockHG.On("SetMetadata", mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
mockHG.On("SetVertex", mock.Anything, mock.Anything).Return(nil).Maybe()
|
|
mockHG.On("Commit").Return(map[tries.ShardKey][][]byte{tries.ShardKey{L1: [3]byte{}, L2: [32]byte{}}: [][]byte{make([]byte, 74), make([]byte, 74), make([]byte, 74), make([]byte, 74)}}).Maybe()
|
|
mockKeyManager.On("Prove", mock.Anything, mock.Anything, mock.Anything).Return([]byte("signature"), nil).Maybe()
|
|
mockVerEnc.On("GenerateKeyPair").Return(make([]byte, 57), make([]byte, 57), nil).Maybe()
|
|
mockBulletproofProver.On("ProveCreate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte("proof"), nil).Maybe()
|
|
mockBulletproofProver.On("VerifyHidden", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true).Maybe()
|
|
mockBulletproofProver.On("VerifyRangeProof", mock.Anything, mock.Anything, mock.Anything).Return(true)
|
|
mockBulletproofProver.On("SumCheck", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true)
|
|
|
|
globalEngine, err := engines.NewTokenExecutionEngine(
|
|
logger,
|
|
mockHG,
|
|
mockClockStore,
|
|
mockKeyManager,
|
|
mockInclusionProver,
|
|
mockBulletproofProver,
|
|
mockVerEnc,
|
|
mockDecaf,
|
|
engines.GlobalMode,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
deploy := createTokenDeployPayloadFull(t, mockHG)
|
|
deployReq, _ := deploy.ToCanonicalBytes()
|
|
// Deploy message should work
|
|
deployMsg := &protobufs.Message{
|
|
Address: token.TOKEN_BASE_DOMAIN[:],
|
|
Payload: deployReq,
|
|
}
|
|
|
|
state := hgstate.NewHypergraphState(mockHG)
|
|
responses, err := globalEngine.ProcessMessage(2, big.NewInt(1), token.TOKEN_BASE_DOMAIN[:], deployMsg.Payload, state)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, responses)
|
|
err = responses.State.Commit()
|
|
assert.NoError(t, err)
|
|
|
|
// Mock that token exists for the second call
|
|
mockVertex := new(mocks.MockVertex)
|
|
mockHG.On("GetVertex", vertexAddr).Return(mockVertex, nil).Once()
|
|
metadataTree := &tries.VectorCommitmentTree{}
|
|
|
|
// Create test configuration
|
|
config := createMintableTestConfig()
|
|
|
|
// Create the metadata tree with valid configuration
|
|
rdfMultiprover := schema.NewRDFMultiprover(&schema.TurtleRDFParser{}, mockInclusionProver)
|
|
configTree, err := token.NewTokenConfigurationMetadata(config, rdfMultiprover)
|
|
require.NoError(t, err)
|
|
|
|
// Store consensus tree
|
|
consensus := &tries.VectorCommitmentTree{}
|
|
consensusData, _ := tries.SerializeNonLazyTree(consensus)
|
|
require.NoError(t, metadataTree.Insert([]byte{0 << 2}, consensusData, nil, big.NewInt(int64(len(consensusData)))))
|
|
|
|
// Store sumcheck tree
|
|
sumcheck := &tries.VectorCommitmentTree{}
|
|
sumcheckData, _ := tries.SerializeNonLazyTree(sumcheck)
|
|
require.NoError(t, metadataTree.Insert([]byte{1 << 2}, sumcheckData, nil, big.NewInt(int64(len(sumcheckData)))))
|
|
|
|
// Store RDF schema
|
|
rdfschema, _ := newTokenRDFHypergraphSchema(vertexAddr[:32], config)
|
|
require.NoError(t, metadataTree.Insert([]byte{2 << 2}, []byte(rdfschema), nil, big.NewInt(int64(len(rdfschema)))))
|
|
|
|
// Store config metadata at the right index
|
|
configBytes, err := tries.SerializeNonLazyTree(configTree)
|
|
require.NoError(t, err)
|
|
require.NoError(t, metadataTree.Insert([]byte{16 << 2}, configBytes, nil, big.NewInt(int64(len(configBytes)))))
|
|
|
|
mockHG.On("GetVertexData", mock.Anything).Return(metadataTree, nil)
|
|
|
|
payload2, _ := createTokenTransactionPayload(t).ToCanonicalBytes()
|
|
|
|
// Transaction should fail in global mode
|
|
txMsg := &protobufs.Message{
|
|
Address: testAddr,
|
|
Payload: payload2,
|
|
}
|
|
|
|
state = hgstate.NewHypergraphState(mockHG)
|
|
_, err = globalEngine.ProcessMessage(2, big.NewInt(1), testAddr, txMsg.Payload, state)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
// Helper functions
|
|
func createTokenDeployPayloadFull(t *testing.T, mockHG *mocks.MockHypergraph) *protobufs.MessageBundle {
|
|
deploy := &token.TokenDeploy{
|
|
Config: &token.TokenIntrinsicConfiguration{
|
|
Name: "Test Token",
|
|
Symbol: "TEST",
|
|
Supply: big.NewInt(100000),
|
|
Units: big.NewInt(10),
|
|
Behavior: token.Acceptable | token.Divisible,
|
|
},
|
|
RDFSchema: []byte("context"),
|
|
}
|
|
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)
|
|
}
|
|
|
|
return &protobufs.MessageBundle{
|
|
Requests: []*protobufs.MessageRequest{
|
|
payment,
|
|
{
|
|
Request: &protobufs.MessageRequest_TokenDeploy{
|
|
TokenDeploy: deploy.ToProtobuf(),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func createTokenTransactionPayload(t *testing.T) *protobufs.MessageRequest {
|
|
// Create mock dependencies
|
|
mockHG := new(mocks.MockHypergraph)
|
|
mockBP := new(mocks.MockBulletproofProver)
|
|
mockBP.On("GenerateRangeProofFromBig", mock.Anything, mock.Anything, mock.Anything).Return(crypto.RangeProofResult{
|
|
Proof: make([]byte, 56),
|
|
Commitment: make([]byte, 112),
|
|
Blinding: make([]byte, 112),
|
|
}, nil)
|
|
mockBP.On("SignHidden", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(make([]byte, 336))
|
|
mockIP := new(mocks.MockInclusionProver)
|
|
mockIP.On("CommitRaw", mock.Anything, mock.Anything).Return(make([]byte, 74), nil)
|
|
mockMultiproof := new(mocks.MockMultiproof)
|
|
mockMultiproof.On("FromBytes", mock.Anything).Return(nil)
|
|
mockMultiproof.On("ToBytes").Return([]byte{}, nil)
|
|
mockIP.On("ProveMultiple", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(mockMultiproof).Maybe()
|
|
mockVE := new(mocks.MockVerifiableEncryptor)
|
|
mockDC := new(mocks.MockDecafConstructor)
|
|
mockKM := new(mocks.MockKeyManager)
|
|
mockKM.On("GetAgreementKey", "q-view-key").Return(&mocks.MockDecafAgreement{}, nil)
|
|
mockKM.On("GetAgreementKey", "q-spend-key").Return(&mocks.MockDecafAgreement{}, nil)
|
|
mockHG.On("GetVertex", mock.Anything).Return(nil, nil)
|
|
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()
|
|
|
|
// Mock token configuration
|
|
tokenconfig := &token.TokenIntrinsicConfiguration{
|
|
Behavior: token.Divisible | token.Acceptable,
|
|
Units: big.NewInt(8), // Divisible tokens need units >= 8
|
|
Name: "Test Token",
|
|
Symbol: "TEST",
|
|
}
|
|
|
|
// Create test domain
|
|
domain := make([]byte, 32)
|
|
rand.Read(domain)
|
|
|
|
tr := &tries.VectorCommitmentTree{}
|
|
tr.Insert([]byte{0}, []byte{0, 0, 0, 0, 0, 0, 0, 0}, nil, big.NewInt(0))
|
|
tr.Insert([]byte{1 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{2 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{3 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{4 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{5 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{6 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{7 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{8 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{9 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{10 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
tr.Insert([]byte{11 << 2}, make([]byte, 64), nil, big.NewInt(0))
|
|
tr.Insert([]byte{12 << 2}, make([]byte, 56), nil, big.NewInt(0))
|
|
|
|
tybi, _ := poseidon.HashBytes(slices.Concat(make([]byte, 32), []byte("pending:PendingTransaction")))
|
|
ty := tybi.FillBytes(make([]byte, 32))
|
|
tr.Insert(slices.Repeat([]byte{0xff}, 32), ty, nil, big.NewInt(0))
|
|
mockHG.On("GetVertexData", mock.Anything).Return(tr, nil)
|
|
|
|
// Create mock inputs
|
|
input1, _ := token.NewTransactionInput(make([]byte, 64))
|
|
input2, _ := token.NewTransactionInput(make([]byte, 64))
|
|
|
|
// Create mock outputs (mock keys)
|
|
mockVK := make([]byte, 56)
|
|
mockSK := make([]byte, 56)
|
|
rand.Read(mockVK)
|
|
rand.Read(mockSK)
|
|
out1, _ := token.NewTransactionOutput(big.NewInt(7), mockVK, mockSK)
|
|
out2, _ := token.NewTransactionOutput(big.NewInt(2), mockVK, mockSK)
|
|
rdf, _ := newTokenRDFHypergraphSchema(domain, tokenconfig)
|
|
// Create transaction
|
|
tx := token.NewTransaction(
|
|
[32]byte(domain),
|
|
[]*token.TransactionInput{input1, input2},
|
|
[]*token.TransactionOutput{out1, out2},
|
|
[]*big.Int{big.NewInt(1), big.NewInt(2)},
|
|
tokenconfig,
|
|
mockHG,
|
|
mockBP,
|
|
mockIP,
|
|
mockVE,
|
|
mockDC,
|
|
keys.ToKeyRing(mockKM, false),
|
|
rdf,
|
|
schema.NewRDFMultiprover(&schema.TurtleRDFParser{}, mockIP),
|
|
)
|
|
|
|
// Mock the Prove call to set required fields
|
|
tx.RangeProof = make([]byte, 100) // Mock range proof
|
|
|
|
err := tx.Prove(0)
|
|
require.NoError(t, err)
|
|
tx.TraversalProof = &tries.TraversalProof{
|
|
Multiproof: mockMultiproof,
|
|
SubProofs: []tries.TraversalSubProof{
|
|
{
|
|
Commits: [][]byte{make([]byte, 64)},
|
|
Ys: [][]byte{make([]byte, 64)},
|
|
Paths: [][]uint64{{0}},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Set signatures on inputs
|
|
for _, input := range tx.Inputs {
|
|
input.Signature = make([]byte, 114) // Ed448 signature size
|
|
rand.Read(input.Signature)
|
|
input.Commitment = make([]byte, 56)
|
|
rand.Read(input.Commitment)
|
|
input.Proofs = [][]byte{make([]byte, 32)}
|
|
}
|
|
|
|
return &protobufs.MessageRequest{
|
|
Request: &protobufs.MessageRequest_Transaction{
|
|
Transaction: tx.ToProtobuf(),
|
|
},
|
|
}
|
|
}
|
|
|
|
func createTokenPendingTransactionPayload(t *testing.T) *protobufs.MessageRequest {
|
|
// Create mock dependencies
|
|
mockHG := new(mocks.MockHypergraph)
|
|
mockBP := new(mocks.MockBulletproofProver)
|
|
mockIP := new(mocks.MockInclusionProver)
|
|
mockVE := new(mocks.MockVerifiableEncryptor)
|
|
mockDC := new(mocks.MockDecafConstructor)
|
|
mockKM := new(mocks.MockKeyManager)
|
|
|
|
// Mock token configuration
|
|
tokenconfig := &token.TokenIntrinsicConfiguration{
|
|
Behavior: token.Divisible | token.Acceptable,
|
|
Units: big.NewInt(8), // Divisible tokens need units >= 8
|
|
Name: "Test Token",
|
|
Symbol: "TEST",
|
|
}
|
|
|
|
// Create test domain
|
|
domain := make([]byte, 32)
|
|
rand.Read(domain)
|
|
|
|
// Create mock inputs
|
|
input1, _ := token.NewPendingTransactionInput(make([]byte, 64))
|
|
|
|
// Create mock outputs (mock keys)
|
|
mockToVK := make([]byte, 56)
|
|
mockToSK := make([]byte, 56)
|
|
mockRefundVK := make([]byte, 56)
|
|
mockRefundSK := make([]byte, 56)
|
|
rand.Read(mockToVK)
|
|
rand.Read(mockToSK)
|
|
rand.Read(mockRefundVK)
|
|
rand.Read(mockRefundSK)
|
|
out1, _ := token.NewPendingTransactionOutput(big.NewInt(9), mockToVK, mockToSK, mockRefundVK, mockRefundSK, 1000)
|
|
|
|
// Create pending transaction
|
|
tx := token.NewPendingTransaction(
|
|
[32]byte(domain),
|
|
[]*token.PendingTransactionInput{input1},
|
|
[]*token.PendingTransactionOutput{out1},
|
|
[]*big.Int{big.NewInt(1)},
|
|
tokenconfig,
|
|
mockHG,
|
|
mockBP,
|
|
mockIP,
|
|
mockVE,
|
|
mockDC,
|
|
keys.ToKeyRing(mockKM, false),
|
|
"", // rdfSchema
|
|
nil, // rdfMultiprover
|
|
)
|
|
|
|
// Mock the Prove call to set required fields
|
|
tx.RangeProof = make([]byte, 100) // Mock range proof
|
|
|
|
// Create a mock multiproof
|
|
mockMultiproof := new(mocks.MockMultiproof)
|
|
mockMultiproof.On("ToBytes").Return(make([]byte, 100), nil)
|
|
|
|
tx.TraversalProof = &tries.TraversalProof{
|
|
Multiproof: mockMultiproof,
|
|
SubProofs: []tries.TraversalSubProof{
|
|
{
|
|
Commits: [][]byte{make([]byte, 64)},
|
|
Ys: [][]byte{make([]byte, 64)},
|
|
Paths: [][]uint64{{0}},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Set signatures on inputs
|
|
for _, input := range tx.Inputs {
|
|
input.Signature = make([]byte, 114) // Ed448 signature size
|
|
rand.Read(input.Signature)
|
|
input.Commitment = make([]byte, 56)
|
|
rand.Read(input.Commitment)
|
|
input.Proofs = [][]byte{make([]byte, 32)}
|
|
}
|
|
|
|
return &protobufs.MessageRequest{
|
|
Request: &protobufs.MessageRequest_PendingTransaction{
|
|
PendingTransaction: tx.ToProtobuf(),
|
|
},
|
|
}
|
|
}
|
|
|
|
func createTokenMintTransactionPayload(t *testing.T) *protobufs.MessageRequest {
|
|
// Create mock dependencies
|
|
mockHG := new(mocks.MockHypergraph)
|
|
mockBP := new(mocks.MockBulletproofProver)
|
|
mockIP := new(mocks.MockInclusionProver)
|
|
mockVE := new(mocks.MockVerifiableEncryptor)
|
|
mockDC := new(mocks.MockDecafConstructor)
|
|
mockKM := new(mocks.MockKeyManager)
|
|
|
|
// Mock token configuration with mint strategy
|
|
tokenconfig := &token.TokenIntrinsicConfiguration{
|
|
Behavior: token.Mintable | token.Divisible,
|
|
MintStrategy: &token.TokenMintStrategy{
|
|
MintBehavior: token.MintWithProof,
|
|
ProofBasis: token.ProofOfMeaningfulWork,
|
|
},
|
|
Units: big.NewInt(1),
|
|
Name: "Test Token",
|
|
Symbol: "TEST",
|
|
}
|
|
|
|
// Create test domain
|
|
domain := make([]byte, 32)
|
|
rand.Read(domain)
|
|
|
|
// Create mock mint input with output data
|
|
outputData := make([]byte, 200) // Mock output data
|
|
rand.Read(outputData)
|
|
input, _ := token.NewMintTransactionInput(big.NewInt(10000), outputData)
|
|
|
|
// Create mock outputs (mock keys)
|
|
mockVK := make([]byte, 56)
|
|
mockSK := make([]byte, 56)
|
|
rand.Read(mockVK)
|
|
rand.Read(mockSK)
|
|
out, _ := token.NewMintTransactionOutput(big.NewInt(10000), mockVK, mockSK)
|
|
|
|
// Create mint transaction
|
|
tx := token.NewMintTransaction(
|
|
[32]byte(domain),
|
|
[]*token.MintTransactionInput{input},
|
|
[]*token.MintTransactionOutput{out},
|
|
[]*big.Int{big.NewInt(1)},
|
|
tokenconfig,
|
|
mockHG,
|
|
mockBP,
|
|
mockIP,
|
|
mockVE,
|
|
mockDC,
|
|
keys.ToKeyRing(mockKM, false),
|
|
"", // rdfSchema
|
|
nil, // rdfMultiprover
|
|
&mocks.MockClockStore{},
|
|
)
|
|
|
|
// Mock the Prove call to set required fields
|
|
tx.RangeProof = make([]byte, 100) // Mock range proof
|
|
|
|
// Set signatures on inputs
|
|
for _, input := range tx.Inputs {
|
|
input.Signature = make([]byte, 114) // Ed448 signature size
|
|
rand.Read(input.Signature)
|
|
input.Commitment = make([]byte, 56)
|
|
rand.Read(input.Commitment)
|
|
input.Proofs = [][]byte{make([]byte, 32)}
|
|
}
|
|
|
|
return &protobufs.MessageRequest{
|
|
Request: &protobufs.MessageRequest_MintTransaction{
|
|
MintTransaction: tx.ToProtobuf(),
|
|
},
|
|
}
|
|
}
|
|
|
|
func createNonTokenPayload(t *testing.T) *protobufs.MessageRequest {
|
|
return &protobufs.MessageRequest{
|
|
Request: &protobufs.MessageRequest_Confirm{
|
|
Confirm: &protobufs.ProverConfirm{
|
|
Filter: []byte{},
|
|
FrameNumber: 1,
|
|
PublicKeySignatureBls48581: &protobufs.BLS48581AddressedSignature{
|
|
Address: make([]byte, 32),
|
|
Signature: make([]byte, 74),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|