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

Modify PRE operator schema's entity #11

Merged
merged 3 commits into from
Jun 17, 2022
Merged

Modify PRE operator schema's entity #11

merged 3 commits into from
Jun 17, 2022

Conversation

manumonti
Copy link
Member

Note: This PR must be merged after graphprotocol/graph-tooling#1108.

Schema's changes:

  • Entity name changed to PREOperator, which is more descriptive.
  • Added OperatorBonded event handler, so PREOperator instance is created when a new operator is bonded.
  • Added confirmationTimestamp field, which will store the time in which the operator is confirmed.

Other changes:

  • Update getEpochStakeId function. This function from utils returns a string with the Epoch Stake's ID. Now it accepts an epoch ID. If this is not passed, it takes the current epoch count. Also, the staking provider argument type have changed from String to Address for simplicity.

@manumonti manumonti requested review from cygnusv and r-czajkowski May 27, 2022 12:30
@manumonti manumonti mentioned this pull request May 27, 2022
@manumonti manumonti marked this pull request as draft June 7, 2022 16:41
@manumonti manumonti marked this pull request as ready for review June 8, 2022 07:49
A stake can have different stake types at the same time (T, NuInTStake
and KeepInTStake), so the StakeType's field can be misleading.
- Entity name changed to PREOperator, which is more descriptive.
- Added OperatorBonded event handler, so PREOperator instance is
created when a new operator is bonded.
- Added confirmationTimestamp field, which will store the time in which
the operator is confirmed.
- Update getEpochStakeId function to accept epoch ID. If no argument
passed, the function takes the current epoch count.
@@ -78,10 +78,11 @@ type TokenholderDelegation implements Delegation @entity {
delegators: [Account!] @derivedFrom(field: "delegatee")
}

type ConfirmedOperator @entity {
type PREOperator @entity {
# ID is the staking provider address
id: ID!
Copy link
Contributor

Choose a reason for hiding this comment

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

I think ID should be the operator address, not the staking provider because we are in the PREOperator entity and we should add a relationship between PREOperator and StakeData entity.

Copy link
Member Author

@manumonti manumonti Jun 14, 2022

Choose a reason for hiding this comment

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

That's a good point. I agree with ID being the operator's address.

But I don't see clearly how to add a relationship between PREOperator and StakeData. Do you mean a Reverse Lookup? This will imply to add a new field in StakeData (probably called preoperator), and in my opinion, we shouldn't mix Threshold Network Staking (StakeData) with an Threshold application of the network (PRE).

Or maybe you mean to use One-To-Many relationship? In that case, do you agree with this schema?

type PREOperator @entity {
  # ID is the operator address
  id: ID!
  confirmationTimestamp: BigInt
  stakes: [StakeData!]!
}

The PREOperator entity will include an array of all stakeDatas that use this operator.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep makes sense. But it should probably be a one-to-one relationship because of this requirement https://github.com/nucypher/nucypher-contracts/blob/main/contracts/contracts/SimplePREApplication.sol#L193 cc @cygnusv.

Another solution could be a schema like this:

type StakeData @entity {
  ...
  applications: [Application!] @derivedFrom(field: "stake")
}

interface Application {
  id: ID!
  stake: StakeData!
  authorizedStakeAmount: BigInt!
}

type PREApplication implements Application @entity {
  id: ID! // id = "operatorAddress-preapplication"
  stake: StakeData!
  authorizedStakeAmount: BigInt!
  confirmationTimestamp: BigInt!
 ... // other fields related to the pre app
}

// other applications in the future eg. RandomBeaconApplication
type RandomBeaconApplication implement Application @entity {
...
}

So in that case we are ready for multi-staking app authorization and the applications field makes sense in the StakeData entity because we authorize applications to use a given stake. What do you think? @manumonti @cygnusv ofc we can address it in a separate PR just a thought.

Copy link
Member Author

@manumonti manumonti Jun 15, 2022

Choose a reason for hiding this comment

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

I find your proposal very reasonable and I mostly agree with that.

Only one comment about this:

type PREApplication implements Application @entity {
  id: ID! // id = "operatorAddress-preapplication"
  [...]

I think it could be easier to implement this if id is stakingProviderAdress-preapplication. I understand that this entity is PREApplication so ID should include operator address, but there is a case which makes hard to implement this:

Check this line: https://github.com/nucypher/nucypher-contracts/blob/710b68713b5b8fece0d0b1c5de376dba1d7d68e7/contracts/contracts/SimplePREApplication.sol#L206

If I am not wrong, this means that when an operator is unbonded, an operatorBonded event is emitted with these parameters:

  • stakingProvider = staking provider address
  • operator = 0x00000000000000000

(please @cygnusv , @vzotova can you confirm?)

So, if the ID is composed of the operator address, we can't easily find the PREOperator entity in order to modify or delete it when this type of event is received.

What do you think, @r-czajkowski ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, that's right and it works for me. I'm curious about David's opinion.

Copy link

Choose a reason for hiding this comment

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

Unbonding operator will lead to operator = 0x00000000000000000 in an event

Copy link
Contributor

@r-czajkowski r-czajkowski Jun 15, 2022

Choose a reason for hiding this comment

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

So, if the ID is composed of the operator address, we can't easily find the PREOperator entity in order to modify or delete it when this type of event is received.

On the other hand, this is probably a rare scenario (but I'm not sure) and there will be 3 apps (at least for now: tbtc, random beacon, and pre) so I don't mind iterating through applications from the StakeData entity and finding the app which contains -preapplication in the ID and then removing it from the store. Just a thought. Both solutions work for me 👍.

Copy link
Member Author

@manumonti manumonti Jun 16, 2022

Choose a reason for hiding this comment

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

Hi @r-czajkowski. Although I think your proposal scheme fits for Threshold Applications (PREApplication, RandomBeacon, TBTC...), IMHO it can't be applied to SimplePREApplication because:

It doesn't make sense to have an authorizedStakeAmount field in SimplePREApplication since events for authorized stake are not emitted yet.

There is a discussion in progress about these events: threshold-network/solidity-contracts#88 (comment).

I have thought about calling the authorizedStake function from SimplePREApplication contract (https://github.com/nucypher/nucypher-contracts/blob/710b68713b5b8fece0d0b1c5de376dba1d7d68e7/contracts/contracts/SimplePREApplication.sol#L95-L101), but the state of this field won't be synced since no new events are emitted if stake amounts are modified.

In any case, about this:

On the other hand, this is probably a rare scenario (but I'm not sure) and there will be 3 apps (at least for now: tbtc, random beacon, and pre) so I don't mind iterating through applications from the StakeData entity and finding the app which contains -preapplication in the ID and then removing it from the store.

As I understand, this can't work in your proposal schema since the applications field is a derived field. And it is not possible to fetch derived fields in the mappings.ts, since these are built at query time. See https://github.com/graphprotocol/graph-ts/issues/219.

In my opinion, we should create a new issue or PR with your proposed schema and address it when a definitive version of some Threshold application (PREApplication, TBTC, RandomBeacon) is deployed.

Please, let me know your opinion about this.

Copy link
Member Author

Choose a reason for hiding this comment

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

I finally created a issue addressing this. So if @r-czajkowski agree, we can continue the conversation there.

#23

Base automatically changed from schema-cleanup-2 to main June 15, 2022 12:39
@manumonti manumonti requested a review from r-czajkowski June 16, 2022 18:33
src/mapping.ts Outdated
const timestamp = event.params.startTimestamp

const preApplication = getOrCreatePreApplication(stakingProvider)
if (operator == Address.zero()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It is always safer to use === instead of ==, unless there is a really good reason to use ==.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done! thank you for the tip

subgraph.yaml Outdated
@@ -71,11 +71,13 @@ dataSources:
apiVersion: 0.0.5
language: wasm/assemblyscript
entities:
- Operator
- PREOperator
Copy link
Contributor

Choose a reason for hiding this comment

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

We renamed the entity to SimplePREApplication. Let's update here as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch! Done.

The contract used for PRE application is 'SimplePREApplication' instead
of 'PREApplication' since the current version of the app is not the
definitive one.

Also, this GraphQL entity includes a field for 'StakeData', and two
timestamps fields, one for when the operator is bonded and another for
when the operator is confirmed.
Copy link
Contributor

@r-czajkowski r-czajkowski left a comment

Choose a reason for hiding this comment

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

:shipit:

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