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: fetch pledges for a dispute before settling or escalating #82

Merged
merged 6 commits into from
Nov 4, 2024

Conversation

jahabeebs
Copy link
Collaborator

🤖 Linear

Closes GRT-194

Description

  • Idea is to avoid BondEscalationModule_ShouldBeEscalated by fetching pledges for a dispute before trying to settle or escalate

@jahabeebs jahabeebs self-assigned this Oct 31, 2024
Copy link
Collaborator

@0xyaco 0xyaco left a comment

Choose a reason for hiding this comment

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

Sweet PR! Left some comments

Comment on lines 1133 to 1146
private decodeBondEscalationStatus(status: number): BondEscalationStatus {
switch (status) {
case 0:
return "Active";
case 1:
return "Resolved";
case 2:
return "Escalated";
case 3:
return "NoResolution";
default:
throw new Error(`Unknown BondEscalationStatus: ${status}`);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move this method to ProphetCodec class and let's make it throw a ProphetDecodingError (you'll need to pull recently merged changes I think)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment on lines 429 to 437
if (amountFor > amountAgainst) {
await this.protocolProvider.settleDispute(
request.prophetData,
response.prophetData,
dispute.prophetData,
);

this.logger.info(`Dispute ${dispute.id} settled.`);
} else if (amountFor <= amountAgainst) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any particular reason to be using less than and gte?

Suggested change
if (amountFor > amountAgainst) {
await this.protocolProvider.settleDispute(
request.prophetData,
response.prophetData,
dispute.prophetData,
);
this.logger.info(`Dispute ${dispute.id} settled.`);
} else if (amountFor <= amountAgainst) {
if (amountFor !=== amountAgainst) {
await this.protocolProvider.settleDispute(
request.prophetData,
response.prophetData,
dispute.prophetData,
);
this.logger.info(`Dispute ${dispute.id} settled.`);
} else if (amountFor === amountAgainst) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🤦🏻‍♂️ I don't know why I thought escalation would happen if the against was greater but thanks for catching that

@@ -489,42 +489,30 @@ describe("EboActor", () => {
});

describe("settleDispute", () => {
it("escalates dispute when BondEscalationModule_ShouldBeEscalated error occurs", async () => {
it("escalates dispute when amountOfPledgesForDispute <= amountOfPledgesAgainstDispute", async () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remember to change this test and the next one too:

Suggested change
it("escalates dispute when amountOfPledgesForDispute <= amountOfPledgesAgainstDispute", async () => {
it("escalates dispute when amountOfPledgesForDispute === amountOfPledgesAgainstDispute", async () => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment on lines 497 to 501
vi.spyOn(protocolProvider.read, "getEscalation").mockResolvedValue({
disputeId: dispute.id,
status: "Active",
amountOfPledgesForDispute: BigInt(5),
amountOfPledgesAgainstDispute: BigInt(10),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sweet case for DI advantages here 😎

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tried doing DI with buildEboActor and passing in a protocolProvider with custom getEscalation but I actually think this isn't ideal here because the eboActor mocks file has so many default vi.spyOn statements already that if we were to refactor buildEboActor now to pass in a custom protocolProvider we would have to define all of those vi.spyOn statements already in eboActor.mocks.ts in the custom protocolProvider object that we pass in like...

const mockProtocolProvider = {
  read: {
    getEscalation: vi.fn().mockResolvedValue({
      disputeId: dispute.id,
      status: "Active",
      amountOfPledgesForDispute: BigInt(10),
      amountOfPledgesAgainstDispute: BigInt(5),
    }),
  },
  getCurrentEpoch: vi.fn().mockResolvedValue({
    number: BigInt(1),
    firstBlockNumber: BigInt(100),
    startTimestamp: BigInt(Date.now()) as UnixTimestamp,
  }),
  settleDispute: vi.fn().mockResolvedValue(undefined),
  // a ton more methods here
} as unknown as ProtocolProvider;

so, if we were to accept a custom protocolProvider object in buildEboActor we would not only have to refactor buildEboActor to not invoke a bunch of the existing vi.spyOn calls we already have there but we'd also have to pass in much larger mock protocolProvider objects in each of our tests rather than using the defaults we have in buildEboActor already

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh yeah, I was just praising the usage of protocolProvider as a dependency! Which made the test super easy to test with this single mock.

@@ -421,13 +421,28 @@ export class EboActor {
try {
this.logger.info(`Settling dispute ${dispute.id}...`);

// OPTIMIZE: check for pledges to potentially save the ShouldBeEscalated error
const escalationData = await this.protocolProvider.read.getEscalation(request.id);
Copy link
Collaborator

@0xyaco 0xyaco Nov 1, 2024

Choose a reason for hiding this comment

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

We should wrap this protocolProvider call in a different try-catch, log the error and return as we don't want to compromise the whole actor because a read operation was not successful.

Suggested change
const escalationData = await this.protocolProvider.read.getEscalation(request.id);
try {
const escalationData = await this.protocolProvider.read.getEscalation(request.id);
} catch (err) {
// log
return; // Will be retried again later
}
try {
// Logic to settle/escalate
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

await expect(actor["settleDispute"](request, response, dispute)).rejects.toThrow(
settleError,
);
});

it("settles dispute when amountOfPledgesForDispute > amountOfPledgesAgainstDispute", async () => {
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("settles dispute when amountOfPledgesForDispute > amountOfPledgesAgainstDispute", async () => {
it("settles dispute when amountOfPledgesForDispute !== amountOfPledgesAgainstDispute", async () => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

const responseToSettle = mocks.buildResponse(request, { id: "0x10" as ResponseId });

const responseToSettle = mocks.buildResponse(request, {
id: ("0x" + "02".repeat(32)) as ResponseId,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you could also use viem's pad function; just wanted to mention it!

Suggested change
id: ("0x" + "02".repeat(32)) as ResponseId,
id: pad("0x02") as ResponseId,

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oops forgot about that, thanks! I replaced all my .replace statements with this

Copy link
Collaborator

@0xnigir1 0xnigir1 left a comment

Choose a reason for hiding this comment

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

nice ser, nothing to add to Yaco's comments

…dges-before

# Conflicts:
#	packages/automated-dispute/tests/mocks/eboActor.mocks.ts
#	packages/automated-dispute/tests/services/eboActor/onDisputeStatusUpdated.spec.ts
@jahabeebs jahabeebs requested review from 0xyaco and 0xnigir1 November 2, 2024 04:09
Copy link
Collaborator

@0xyaco 0xyaco left a comment

Choose a reason for hiding this comment

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

Two minor tweaks and it's ready to go!

case 3:
return "NoResolution";
default:
throw new ProphetDecodingError(id, toHex(status.toString()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

This ID is to help us identify the property that was decoded!

Suggested change
throw new ProphetDecodingError(id, toHex(status.toString()));
throw new ProphetDecodingError("escalation.status", toHex(status.toString()));

You can remove the id param from this method too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@@ -564,22 +564,22 @@ describe("EboActor", () => {
);
});

it("settles dispute when amountOfPledgesForDispute > amountOfPledgesAgainstDispute", async () => {
it("settles dispute when amountOfPledgesForDispute !== amountOfPledgesAgainstDispute", async () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Given that this is an extremely core case, let's explicitly test both cases here: > and <

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

✅ I split this into two test cases

@jahabeebs jahabeebs requested a review from 0xyaco November 4, 2024 16:30
0xyaco
0xyaco previously approved these changes Nov 4, 2024
0xnigir1
0xnigir1 previously approved these changes Nov 4, 2024
# 🤖 Linear

Closes GRT-194

## Description
- Escalates dispute to arbitrator
@jahabeebs jahabeebs dismissed stale reviews from 0xnigir1 and 0xyaco via 3d9399f November 4, 2024 19:36
@jahabeebs jahabeebs requested review from 0xnigir1 and 0xyaco November 4, 2024 19:48
@jahabeebs jahabeebs merged commit 436a9a8 into dev Nov 4, 2024
5 checks passed
@jahabeebs jahabeebs deleted the feat/grt-145-fetch-pledges-before branch November 4, 2024 19:52
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