-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: build onRequestCreated #18
Changes from 9 commits
6cf15f3
6bb11e6
40f0e03
6c7e02e
c8d6702
03e75c7
bd3f0db
33271d7
6647610
4a16f80
be694f1
c9bca60
2aba0ac
a91e4ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,68 @@ | ||
import { BlockNumberService } from "@ebo-agent/blocknumber"; | ||
import { Caip2ChainId } from "@ebo-agent/blocknumber/dist/types.js"; | ||
import { ILogger } from "@ebo-agent/shared"; | ||
|
||
import { RequestMismatch } from "./exceptions/requestMismatch.js"; | ||
import { EboRegistry } from "./interfaces/eboRegistry.js"; | ||
import { ProtocolProvider } from "./protocolProvider.js"; | ||
import { EboEvent } from "./types/events.js"; | ||
import { Dispute, Response } from "./types/prophet.js"; | ||
|
||
export class EboActor { | ||
private requestActivity: unknown[]; | ||
|
||
constructor( | ||
private readonly protocolProvider: ProtocolProvider, | ||
private readonly blockNumberService: BlockNumberService, | ||
private readonly registry: EboRegistry, | ||
private readonly requestId: string, | ||
) { | ||
this.requestActivity = []; | ||
private readonly logger: ILogger, | ||
) {} | ||
|
||
/** | ||
* Handle RequestCreated event. | ||
* | ||
* @param event RequestCreated event | ||
*/ | ||
public async onRequestCreated(event: EboEvent<"RequestCreated">): Promise<void> { | ||
if (event.metadata.requestId != this.requestId) | ||
throw new RequestMismatch(this.requestId, event.metadata.requestId); | ||
|
||
this.registry.addRequest(event.metadata.requestId, event.metadata.request); | ||
|
||
const { chainId } = event.metadata; | ||
const { currentEpoch, currentEpochTimestamp } = | ||
await this.protocolProvider.getCurrentEpoch(); | ||
|
||
const epochBlockNumber = await this.blockNumberService.getEpochBlockNumber( | ||
currentEpochTimestamp, | ||
chainId, | ||
); | ||
|
||
if (this.alreadyProposed(currentEpoch, chainId, epochBlockNumber)) return; | ||
|
||
await this.protocolProvider.proposeResponse( | ||
this.requestId, | ||
currentEpoch, | ||
chainId, | ||
epochBlockNumber, | ||
); | ||
} | ||
|
||
public async onRequestCreated(_event: EboEvent<"RequestCreated">): Promise<void> { | ||
// TODO: implement | ||
return; | ||
private alreadyProposed(epoch: bigint, chainId: Caip2ChainId, blockNumber: bigint) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also , we should add an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it make sense to have a new propose with the same block? I'd think that if there has already been a proposal with the block N, rejected or not, the agent wouldn't want to propose the same block N again. I might be missing something though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Left this as |
||
const responses = this.registry.getResponses(); | ||
|
||
for (const [responseId, response] of responses) { | ||
if (response.response.block != blockNumber) continue; | ||
if (response.response.chainId != chainId) continue; | ||
if (response.response.epoch != epoch) continue; | ||
|
||
this.logger.info( | ||
`Block ${blockNumber} for epoch ${epoch} and chain ${chainId} already proposed on response ${responseId}. Skipping...`, | ||
); | ||
|
||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public async onResponseProposed(_event: EboEvent<"ResponseDisputed">): Promise<void> { | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,22 @@ | ||||||||||||||
import { EboRegistry } from "./interfaces/eboRegistry.js"; | ||||||||||||||
import { Dispute, Request, Response } from "./types/prophet.js"; | ||||||||||||||
|
||||||||||||||
export class EboMemoryRegistry implements EboRegistry { | ||||||||||||||
private requests: Map<string, Request>; | ||||||||||||||
private responses: Map<string, Response>; | ||||||||||||||
private dispute: Map<string, Dispute>; | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
constructor() { | ||||||||||||||
this.requests = new Map(); | ||||||||||||||
this.responses = new Map(); | ||||||||||||||
this.dispute = new Map(); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
public addRequest(requestId: string, request: Request) { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ooaa nice, didn't know that. however, vscode is so magical that doesn't need this tag xd |
||||||||||||||
this.requests.set(requestId, request); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
public getResponses() { | ||||||||||||||
return this.responses; | ||||||||||||||
} | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export class RequestMismatch extends Error { | ||
constructor(requestId: string, eventRequestId: string) { | ||
super(`Actor handling request ${requestId} received a request ${eventRequestId} event.`); | ||
this.name = "RequestMismatch"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Request, Response } from "../types/prophet.js"; | ||
|
||
export interface EboRegistry { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lets add a high level description here |
||
/** | ||
* Add a `Request` by ID. | ||
* | ||
* @param requestId the ID of the `Request` | ||
* @param request the `Request` | ||
*/ | ||
addRequest(requestId: string, request: Request): void; | ||
|
||
/** | ||
* Return all responses | ||
* | ||
* @returns responses map | ||
*/ | ||
getResponses(): Map<string, Response>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import { Caip2ChainId } from "@ebo-agent/blocknumber/dist/types.js"; | ||
import { Log } from "viem"; | ||
|
||
import { Dispute, Request } from "./prophet.js"; | ||
import { Dispute, Request, Response } from "./prophet.js"; | ||
|
||
export type EboEventName = | ||
| "NewEpoch" | ||
|
@@ -17,14 +18,17 @@ export interface NewEpoch { | |
epochBlockNumber: bigint; | ||
} | ||
|
||
export interface ResponseCreated { | ||
export interface ResponseProposed { | ||
requestId: string; | ||
request: Request; | ||
responseId: string; | ||
response: Response; | ||
} | ||
|
||
export interface RequestCreated { | ||
requestId: string; | ||
epoch: bigint; | ||
chainId: Caip2ChainId; | ||
request: Request; | ||
requestId: string; | ||
} | ||
|
||
export interface ResponseDisputed { | ||
|
@@ -60,8 +64,8 @@ export type EboEventData<E extends EboEventName> = E extends "NewEpoch" | |
? NewEpoch | ||
: E extends "RequestCreated" | ||
? RequestCreated | ||
: E extends "ResponseCreated" | ||
? ResponseCreated | ||
: E extends "ResponseProposed" | ||
? ResponseProposed | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤣 |
||
: E extends "ResponseDisputed" | ||
? ResponseDisputed | ||
: E extends "DisputeStatusChanged" | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,3 +1,4 @@ | ||||||
import { Caip2ChainId } from "@ebo-agent/blocknumber/dist/types.js"; | ||||||
import { Address } from "viem"; | ||||||
|
||||||
export interface Request { | ||||||
|
@@ -13,7 +14,13 @@ export interface Request { | |||||
export interface Response { | ||||||
proposer: Address; | ||||||
requestId: string; | ||||||
response: Uint8Array; | ||||||
|
||||||
// To be byte-encode when sending it to Prophet | ||||||
response: { | ||||||
chainId: Caip2ChainId; // Pending on-chain definition on CAIP-2 usage | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
block: bigint; | ||||||
epoch: bigint; | ||||||
}; | ||||||
} | ||||||
|
||||||
export interface Dispute { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should handle the case in which proposeResponse fails, if it is an rpc failure or if a propose was already posted for the requestId