Skip to content
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

Merged
merged 14 commits into from
Aug 8, 2024
Merged

feat: build onRequestCreated #18

merged 14 commits into from
Aug 8, 2024

Conversation

0xyaco
Copy link
Collaborator

@0xyaco 0xyaco commented Aug 5, 2024

🤖 Linear

Closes GRT-81 GRT-77

Description

  • Standardizes timestamps used through our providers to BigInt type, to be consistent with viem Block.timestamp type
  • Set up EboActor.onRequestCreated handler

Copy link

linear bot commented Aug 5, 2024

GRT-81 Implement onRequestCreated

We want the actors to handle the event RequestCreated from prophet Orcale.

This handler should:

  • Update RequestActivity
  • Validate if there was a proposal already created ? or maybe wait for a revert (TBD)
  • Leverage BlockNumberService to obtain block numbers from supported chains based on the epoch timestamp.
  • Propose a response
  • Handle the case in which a proposal was already created

Event: https://github.com/defi-wonderland/prophet-core/blob/d01bc1a0fe39d516ff502a669e80b8eb2fe2df86/solidity/interfaces/IOracle.sol#L20

Follow figma sequence diagram: https://www.figma.com/board/BbciqJb5spg35ZglTsRRBb/Offchain?node-id=239-2711&t=y06FKcx0NVro4Jml-4

AC:

  • Event handler successfully implemented
  • Unit tests

@0xyaco 0xyaco changed the title feat: [WIP] build onRequestCreated feat: build onRequestCreated Aug 6, 2024
@0xyaco 0xyaco marked this pull request as ready for review August 6, 2024 22:56
@0xyaco 0xyaco requested review from 0xkenj1 and 0xnigir1 August 6, 2024 22:56

constructor(
private readonly protocolProvider: ProtocolProvider,
private readonly blockNumberService: BlockNumberService,
private readonly requestId: string,
) {
this.requestActivity = [];
this.registry = new EboRegistry();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't the registry be injected as a Dependency here?
also, maybe use an interface IEboRegistry, so if we wanted to later change for a real DB instead of in-memory maps we can easily switch to that. (i understand that the registry is sort of Database/Cache)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably not used now but getRequest should exist right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll probably need that, yep.

Figured we'll add methods in the registry as needed, it'd be easier to know what are we going to use while implementing the EboActor handlers (probably all the get.../add...); there are some edge cases that I want to think about while implemeting the EboActor.

currentEpoch,
chainId,
epochBlockNumber,
);
Copy link
Collaborator

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

public async onRequestCreated(_event: EboEvent<"RequestCreated">): Promise<void> {
// TODO: implement
return;
private alreadyProposed(epoch: bigint, chainId: Caip2ChainId, blockNumber: bigint) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would call this activePropose. We can have a propose on the registry that was already discarded

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also , we should add an isActive field to response object

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left this as alreadyProposed, this will be the last thing to check on the agent side; it'd save it of trying to propose a response that has already been created. The activePropose check is done at the beginning of this method.

Comment on lines 5 to 7
private requests: Map<string, Request>;
private responses: Map<string, Response>;
private dispute: Map<string, Dispute>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private requests: Map<string, Request>;
private responses: Map<string, Response>;
private dispute: Map<string, Dispute>;
private requests: Map<string, Request>= new Map();
private responses: Map<string, Response>= new Map();
private dispute: Map<string, Dispute>= new Map();

Comment on lines 10 to 12
this.requests = new Map();
this.responses = new Map();
this.dispute = new Map();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.requests = new Map();
this.responses = new Map();
this.dispute = new Map();

: E extends "ResponseCreated"
? ResponseCreated
: E extends "ResponseProposed"
? ResponseProposed
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣


// To be byte-encode when sending it to Prophet
response: {
chainId: Caip2ChainId; // Pending on-chain definition on CAIP-2 usage
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
chainId: Caip2ChainId; // Pending on-chain definition on CAIP-2 usage
chainId: Caip2ChainId; //FIXME/TODO: Pending on-chain definition on CAIP-2 usage

@@ -0,0 +1,18 @@
import { Request, Response } from "../types/prophet.js";

export interface EboRegistry {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets add a high level description here

this.dispute = new Map();
}

public addRequest(requestId: string, request: Request) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public addRequest(requestId: string, request: Request) {
/** @inheritdoc */
public addRequest(requestId: string, request: Request) {

Copy link
Collaborator

Choose a reason for hiding this comment

The 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

public addRequest(requestId: string, request: Request) {
this.requests.set(requestId, request);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** @inheritdoc */

@0xnigir1
Copy link
Collaborator

0xnigir1 commented Aug 7, 2024

i don't have the business context, if onRequestCreated is called twice on a row, is it possible that the event has different metadata? if yes, is it correct that the request entry on EboMemoryRegistry is overridden (since the requestId is always the same for an EboAgent instance)?

@0xkenj1
Copy link
Collaborator

0xkenj1 commented Aug 7, 2024

Each EboActor is responsible to handle a single and unique requestId, and also each of the EboAgents have its own EboRegistry.

Not sure if i got it, but maybe this info answers your question @0xnigir1

@0xyaco
Copy link
Collaborator Author

0xyaco commented Aug 7, 2024

That's right, by design each EboActor will be called with onRequestCreated once. If for some reason this is called multiple times, Prophet's contracts are not working as expected and everything is probably in flames on the contracts side.

I like the idea of adding a check for already having a request though, a nice case for using logger.critical 🚒

Comment on lines +41 to +49
if (this.anyActiveProposal()) {
// Skipping new proposal until the actor receives a ResponseDisputed event;
// at that moment, it will be possible to re-propose again.
this.logger.info(
`There is an active proposal for request ${this.requestId}. Skipping...`,
);

return;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xkenj1 included this check prior starting to build the Response (any response will be ignored if there's an active proposal)

public async onRequestCreated(_event: EboEvent<"RequestCreated">): Promise<void> {
// TODO: implement
return;
private alreadyProposed(epoch: bigint, chainId: Caip2ChainId, blockNumber: bigint) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left this as alreadyProposed, this will be the last thing to check on the agent side; it'd save it of trying to propose a response that has already been created. The activePropose check is done at the beginning of this method.

@0xyaco 0xyaco requested review from 0xkenj1 and 0xnigir1 August 7, 2024 22:42
0xkenj1
0xkenj1 previously approved these changes Aug 8, 2024

expect(proposeResponseMock).not.toHaveBeenCalled();
});

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it("throws if request was already handled by the actor", () => {
const actor = new EboActor(
protocolProvider,
blockNumberService,
registry,
requestId,
logger,
);
vi.spyOn(registry, "getRequest").mockReturnValue(BASE_REQUEST);
expect(actor.onRequestCreated(requestCreatedEvent)).rejects.toBeInstanceOf(
InvalidActorState,
);
});


import { EboActor } from "../src/eboActor.js";
import { EboMemoryRegistry } from "../src/eboMemoryRegistry.js";
import { RequestMismatch } from "../src/exceptions/requestMismatch.js";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { RequestMismatch } from "../src/exceptions/requestMismatch.js";
import { RequestMismatch } from "../src/exceptions/requestMismatch.js";
import { InvalidActorState } from "../src/exceptions/invalidActorState.exception.js";

this is related to the other comment

@0xyaco 0xyaco merged commit 3933c43 into dev Aug 8, 2024
5 checks passed
@0xyaco 0xyaco deleted the feat/on-request-created branch August 8, 2024 18:11
Copy link

linear bot commented Aug 28, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants