Create mock for ownership and sponsorship
This commit is contained in:
parent
914b71c98a
commit
636b0eb741
131
packages/azimuth-watcher/MOCK_EVENTS.md
Normal file
131
packages/azimuth-watcher/MOCK_EVENTS.md
Normal 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
|
||||
105
packages/azimuth-watcher/src/mock-event-store.ts
Normal file
105
packages/azimuth-watcher/src/mock-event-store.ts
Normal 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();
|
||||
@ -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];
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user