Create mock for ownership and sponsorship

This commit is contained in:
Pranav 2025-10-17 15:38:47 +05:30
parent 914b71c98a
commit 636b0eb741
4 changed files with 267 additions and 1 deletions

View File

@ -0,0 +1,131 @@
# Mock Sponsorship Events
This document describes how to inject mock sponsorship change events into the azimuth-watcher for testing purposes.
## Overview
The azimuth-watcher supports injecting mock events for sponsorship changes (EscapeRequested, EscapeAccepted, EscapeCanceled, LostSponsor) via a GraphQL mutation.
## Usage
### Inject Mock Events
Open the GraphQL playground and run the `injectMockEvents` mutation:
```graphql
mutation {
injectMockEvents(
events: [
{
type: ESCAPE_REQUESTED
point: 256
sponsor: 1
blockNumber: 1000
}
{
type: ESCAPE_ACCEPTED
point: 256
sponsor: 1
blockNumber: 1001
}
]
) {
success
eventsInjected
}
}
```
## Event Types
The following event types are supported:
### Sponsorship Events
- `ESCAPE_REQUESTED` - Star requests to change sponsor
- `ESCAPE_ACCEPTED` - New galaxy accepts the star
- `ESCAPE_CANCELED` - Escape request is canceled (by star or rejected by galaxy)
- `LOST_SPONSOR` - Current galaxy stops sponsoring the star
### Ownership Events
- `OWNER_CHANGED` - Ownership of a point changes
## Example Scenarios
### Successful Sponsor Change
```graphql
mutation {
injectMockEvents(
events: [
{ type: ESCAPE_REQUESTED, point: 256, sponsor: 1, blockNumber: 1000 }
{ type: ESCAPE_ACCEPTED, point: 256, sponsor: 1, blockNumber: 1001 }
]
) {
success
eventsInjected
}
}
```
### Galaxy Detaches Star
```graphql
mutation {
injectMockEvents(
events: [
{ type: LOST_SPONSOR, point: 512, sponsor: 0, blockNumber: 2000 }
]
) {
success
eventsInjected
}
}
```
### Canceled Escape
```graphql
mutation {
injectMockEvents(
events: [
{ type: ESCAPE_REQUESTED, point: 768, sponsor: 2, blockNumber: 3000 }
{ type: ESCAPE_CANCELED, point: 768, sponsor: 2, blockNumber: 3001 }
]
) {
success
eventsInjected
}
}
```
### Ownership Change
```graphql
mutation {
injectMockEvents(
events: [
{ type: OWNER_CHANGED, point: 256, owner: "0x1234567890123456789012345678901234567890", blockNumber: 4000 }
]
) {
success
eventsInjected
}
}
```
## Testing from zenithd
1. Set the azimuth-watcher endpoint:
```bash
export AZIMUTH_WATCHER_ENDPOINT=http://localhost:3001/graphql
```
2. Inject mock events via GraphQL playground (step 2 above)
3. Run zenithd tests - it will receive the mock events through normal GraphQL queries
## Files Modified
- `src/mock-event-store.ts` - In-memory event storage
- `src/schema.gql` - Added mutation and types
- `src/resolvers.ts` - Added mutation resolver and modified `eventsInRange` query

View File

@ -0,0 +1,105 @@
//
// Copyright 2025 DeepStack
//
import { ResultEvent } from '@cerc-io/util';
const AZIMUTH_CONTRACT = '0x223c067F8CF28ae173EE5CafEa60cA44C335fecB';
const MOCK_TX_HASH = '0x0000000000000000000000000000000000000000000000000000000000000000';
const MOCK_FROM_ADDRESS = '0x0000000000000000000000000000000000000000';
export type MockEventType = 'ESCAPE_REQUESTED' | 'ESCAPE_ACCEPTED' | 'ESCAPE_CANCELED' | 'LOST_SPONSOR' | 'OWNER_CHANGED';
export interface MockEventInput {
type: MockEventType;
point: number;
sponsor?: number;
owner?: string;
blockNumber: number;
}
class MockEventStore {
private events: ResultEvent[] = [];
addEvents (inputs: MockEventInput[]): number {
const newEvents = inputs.map((input, index) => this.createMockEvent(input, index));
this.events.push(...newEvents);
return newEvents.length;
}
getEventsInRange (fromBlock: number, toBlock: number, eventName?: string): ResultEvent[] {
return this.events.filter(event => {
const blockNumber = event.block.number;
const matchesRange = blockNumber >= fromBlock && blockNumber <= toBlock;
const matchesName = !eventName || event.event.__typename === `${eventName}Event`;
return matchesRange && matchesName;
});
}
private createMockEvent (input: MockEventInput, eventIndex: number): ResultEvent {
const { type, point, sponsor, owner, blockNumber } = input;
const blockHash = `0x${blockNumber.toString(16).padStart(64, '0')}`;
const parentHash = `0x${(blockNumber - 1).toString(16).padStart(64, '0')}`;
return {
block: {
cid: null,
hash: blockHash,
number: blockNumber,
timestamp: Math.floor(Date.now() / 1000),
parentHash
},
tx: {
hash: MOCK_TX_HASH,
index: 0,
from: MOCK_FROM_ADDRESS,
to: AZIMUTH_CONTRACT
},
contract: AZIMUTH_CONTRACT,
eventIndex,
eventSignature: '',
event: this.createEventData(type, point, sponsor, owner),
proof: ''
};
}
private createEventData (type: MockEventType, point: number, sponsor?: number, owner?: string): any {
switch (type) {
case 'ESCAPE_REQUESTED':
return {
__typename: 'EscapeRequestedEvent',
point: BigInt(point),
sponsor: BigInt(sponsor ?? 0)
};
case 'ESCAPE_ACCEPTED':
return {
__typename: 'EscapeAcceptedEvent',
point: BigInt(point),
sponsor: BigInt(sponsor ?? 0)
};
case 'ESCAPE_CANCELED':
return {
__typename: 'EscapeCanceledEvent',
point: BigInt(point),
sponsor: BigInt(sponsor ?? 0)
};
case 'LOST_SPONSOR':
return {
__typename: 'LostSponsorEvent',
point: BigInt(point),
sponsor: BigInt(sponsor ?? 0)
};
case 'OWNER_CHANGED':
return {
__typename: 'OwnerChangedEvent',
point: BigInt(point),
owner: owner ?? ''
};
default:
throw new Error(`Unknown mock event type: ${type}`);
}
}
}
export const mockEventStore = new MockEventStore();

View File

@ -23,6 +23,7 @@ import {
} from '@cerc-io/util';
import { Indexer } from './indexer';
import { mockEventStore, MockEventInput } from './mock-event-store';
const log = debug('vulcanize:resolver');
@ -105,6 +106,12 @@ export const createResolvers = async (
await indexer.watchContract(address, kind, checkpoint, startingBlock);
return true;
},
injectMockEvents: async (_: any, { events }: { events: MockEventInput[] }): Promise<{ success: boolean, eventsInjected: number }> => {
log('injectMockEvents', events.length);
const eventsInjected = mockEventStore.addEvents(events);
return { success: true, eventsInjected };
}
},
@ -1125,7 +1132,8 @@ export const createResolvers = async (
}
const events = await indexer.getEventsInRange(fromBlockNumber, toBlockNumber, name);
return events.map(event => indexer.getResultEvent(event));
const mockEvents = mockEventStore.getEventsInRange(fromBlockNumber, toBlockNumber, name);
return [...events.map(event => indexer.getResultEvent(event)), ...mockEvents];
}
);
},

View File

@ -174,6 +174,27 @@ type SyncStatus {
latestProcessedBlockNumber: Int!
}
enum MockEventType {
ESCAPE_REQUESTED
ESCAPE_ACCEPTED
ESCAPE_CANCELED
LOST_SPONSOR
OWNER_CHANGED
}
input MockEventInput {
type: MockEventType!
point: Int!
sponsor: Int
owner: String
blockNumber: Int!
}
type MockInjectionResult {
success: Boolean!
eventsInjected: Int!
}
type Query {
events(blockHash: String!, contractAddress: String!, name: String): [ResultEvent!]
eventsInRange(fromBlockNumber: Int!, toBlockNumber: Int!, name: String): [ResultEvent!]
@ -228,6 +249,7 @@ type Query {
type Mutation {
watchContract(address: String!, kind: String!, checkpoint: Boolean!, startingBlock: Int): Boolean!
injectMockEvents(events: [MockEventInput!]!): MockInjectionResult!
}
type Subscription {