Team-Kujira / core

55 stars 38 forks source link

Slashing events format issue? #35

Closed AndreMiras closed 1 year ago

AndreMiras commented 1 year ago

I was exploring slashing events of Kujira lately and I came across something I'm not sure if it's a bug or a feature. Also I'm not sure if it's more a Tendermint bug (fixed in more recent release) or Kujira specific. At block 267445 there's a double signing slashing event on kujiravalcons1zrvl0kldjjuj9z996kak3sju08vyhj8tzy4e5s. However the event is split in 2 while I'm expecting it to be merged as a single object. This is what I get:

[
  [
    {
      "key": "address",
      "value": "kujiravalcons1zrvl0kldjjuj9z996kak3sju08vyhj8tzy4e5s"
    },
    {
      "key": "power",
      "value": "210899"
    },
    {
      "key": "reason",
      "value": "double_sign"
    }
  ],
  [
    {
      "key": "jailed",
      "value": "kujiravalcons1zrvl0kldjjuj9z996kak3sju08vyhj8tzy4e5s"
    }
  ]
]

And this is what I was expecting:

[
  [
    {
      "key": "address",
      "value": "kujiravalcons1zrvl0kldjjuj9z996kak3sju08vyhj8tzy4e5s"
    },
    {
      "key": "power",
      "value": "210899"
    },
    {
      "key": "reason",
      "value": "double_sign"
    },
    {
      "key": "jailed",
      "value": "kujiravalcons1zrvl0kldjjuj9z996kak3sju08vyhj8tzy4e5s"
    }
  ]
]

I've shared below a snippet that I hope clarifies what I mean:

const rpcServer = "https://archive.kujira.network";

interface BlockEventAttribute {
  key: string;
  value: string;
}

interface BlockEvent {
  type: string;
  attributes: BlockEventAttribute[];
}

const decodeAttribute = (attribute: BlockEventAttribute) => {
  const key = Buffer.from(attribute.key, "base64").toString("utf-8");
  const value = Buffer.from(attribute.value, "base64").toString("utf-8");
  return { key, value };
};

const decodeBlockEvent = (blockEvent: BlockEvent): Record<string, string>[] =>
  blockEvent.attributes.map((attribute) => decodeAttribute(attribute));

const decodeBlockEvents = (blockEvents: BlockEvent[]) =>
  blockEvents.map(decodeBlockEvent);

const getBlockResults = async (blockHeight: number) => {
  const url = `${rpcServer}/block_results?height=${blockHeight}`;
  const response = await fetch(url);
  return response.json();
};

const getSlashingEvents = (beginBlockEvents: BlockEvent[]) =>
  beginBlockEvents.filter((event) => event.type === "slash");

const main = async () => {
  const blockHeight = 267445;
  const blockResults = await getBlockResults(blockHeight);
  const beginBlockEvents = blockResults.result.begin_block_events;
  const slashingEvents = getSlashingEvents(beginBlockEvents);
  const decodedBlockEvents = decodeBlockEvents(slashingEvents);
  const decodedBlockEventsJson = JSON.stringify(decodedBlockEvents, null, 2);
  console.log(decodedBlockEventsJson);
};

main().catch(console.error);

I tried to keep third party dependencies small. Code is ran this way:

ts-node src/slash-event-bug.ts

And here is a screenshot of the run on the left and the code on the right. image

codehans commented 1 year ago

This looks correct (as far as the SDK is concerned) - it's emitted as two separate events, on for the jail and one for the slash. That first event you're seeing is the slash - jailing doesn't mandate slashing, and neither does slashing require jailing.

https://github.com/cosmos/cosmos-sdk/blob/main/x/slashing/keeper/keeper.go#L120-L128

https://github.com/cosmos/cosmos-sdk/blob/main/x/slashing/keeper/keeper.go#L140-L145

AndreMiras commented 1 year ago

Hey @codehans, thanks a mil for getting back so fast and sharing this piece of code, that makes sense. I guess I came across more downtime slashing events which in this case send the jailed key part of the other attributes. https://github.com/cosmos/cosmos-sdk/blob/v0.47.4/x/slashing/keeper/infractions.go#L91-L100 So I assumed this was the norm, but I see now. Pretty crazy that double signing wouldn't always lead to jailing, or maybe it should/does, but that's more a CosmosSDK discussion.