-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Do not HTR the state when checking for optimistic mode #12143
Conversation
beacon-chain/rpc/eth/helpers/sync.go
Outdated
return false, errors.Wrapf(err, "could not get block roots for slot %d", slotNumber) | ||
} | ||
if len(roots) == 0 { | ||
// TODO: What to do here? |
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.
Not sure what to do in this case
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.
my suggestion above removes this problem
beacon-chain/rpc/eth/helpers/sync.go
Outdated
if st.Slot() == headSt.Slot() { | ||
return optimisticModeFetcher.IsOptimistic(ctx) | ||
} | ||
r, err := st.LatestBlockHeader().HashTreeRoot() |
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.
doesn't work this way for the reasons we have discussed earlier.
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.
you do not need to do this HTR. All you care is if the block is canonical or not. Here the cheapest thing to do is to pass database
and use database.BlockRootsBySlot
or BlocksBySlot
beacon-chain/rpc/eth/helpers/sync.go
Outdated
if !optimistic { | ||
return false, nil | ||
} | ||
headSt, err := stateFetcher.State(ctx, []byte("head")) |
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.
please use chainInfo.HeadSlot()
beacon-chain/rpc/eth/helpers/sync.go
Outdated
if primitives.Slot(slotNumber) == headSt.Slot() { | ||
return optimisticModeFetcher.IsOptimistic(ctx) | ||
} | ||
finalizedSlot, err := slots.EpochStart(headSt.FinalizedCheckpoint().Epoch) |
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.
please use chainInfo.FinalizedCheckpt()
and move this check before the head check above.
beacon-chain/rpc/eth/helpers/sync.go
Outdated
if primitives.Slot(slotNumber) <= finalizedSlot { | ||
return false, nil | ||
} | ||
_, roots, err := database.BlockRootsBySlot(ctx, primitives.Slot(slotNumber)) |
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.
You can avoid this database lookup in this case by using chainInfo.ForkChoicer().AncestorRoot(ctx, headRoot, slot)
and then checking for optimistic status of that root. Be careful with the forkchoice locks.
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.
Be careful with the forkchoice locks.
Do I need to explicitly do anything?
beacon-chain/rpc/eth/helpers/sync.go
Outdated
return false, errors.Wrapf(err, "could not get block roots for slot %d", slotNumber) | ||
} | ||
if len(roots) == 0 { | ||
// TODO: What to do here? |
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.
my suggestion above removes this problem
beacon-chain/rpc/eth/helpers/sync.go
Outdated
for _, r := range roots { | ||
canonical, err := chainInfo.IsCanonical(ctx, r) | ||
if err != nil { | ||
return false, errors.Wrapf(err, "could not check canonical status") | ||
} | ||
if canonical { | ||
return optimisticModeFetcher.IsOptimisticForRoot(ctx, r) | ||
} | ||
} | ||
// No block is canonical, return true | ||
return true, nil |
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.
My suggestion above removes this block.
beacon-chain/rpc/eth/helpers/sync.go
Outdated
) (bool, error) { | ||
st, err := stateFetcher.State(ctx, stateId) | ||
if err != nil { | ||
return false, errors.Wrap(err, "could not fetch justified state") |
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.
Why this error message?
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.
I forgot to change this when extracting the function
beacon-chain/rpc/eth/helpers/sync.go
Outdated
headSt, err := stateFetcher.State(ctx, []byte("head")) | ||
if err != nil { | ||
return false, errors.Wrap(err, "could not fetch head state") | ||
} | ||
if st.Slot() == headSt.Slot() { | ||
return optimisticModeFetcher.IsOptimistic(ctx) | ||
} |
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.
you are grabbing a state only to check that the incoming id has the same state slot. You can use if you want chainInfo.HeadSlot()
but also you should move this check (which is very unlikely) down the path.
beacon-chain/rpc/eth/helpers/sync.go
Outdated
if st.Slot() == headSt.Slot() { | ||
return optimisticModeFetcher.IsOptimistic(ctx) | ||
} | ||
r, err := st.LatestBlockHeader().HashTreeRoot() |
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.
you do not need to do this HTR. All you care is if the block is canonical or not. Here the cheapest thing to do is to pass database
and use database.BlockRootsBySlot
or BlocksBySlot
beacon-chain/rpc/eth/helpers/sync.go
Outdated
} | ||
if len(roots) == 0 { | ||
// TODO: What to do here? | ||
return false, errors.New("no block") |
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 now have this issue here @potuz
beacon-chain/rpc/eth/helpers/sync.go
Outdated
if err != nil { | ||
return false, errors.Wrap(err, "could not get head state's finalized slot") | ||
} | ||
if primitives.Slot(slotNumber) <= finalizedSlot { |
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.
Please move this check above the head one.
beacon-chain/rpc/eth/helpers/sync.go
Outdated
} | ||
r, err := chainInfo.ForkChoicer().AncestorRoot(ctx, bytesutil.ToBytes32(stateId), primitives.Slot(slotNumber)) | ||
if err != nil { | ||
return false, errors.Wrap(err, "could not get ancestor root") |
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.
on errors is probably better to return true instead of false.
beacon-chain/rpc/eth/helpers/sync.go
Outdated
if primitives.Slot(slotNumber) <= finalizedSlot { | ||
return false, nil | ||
} | ||
r, err := chainInfo.ForkChoicer().AncestorRoot(ctx, bytesutil.ToBytes32(stateId), primitives.Slot(slotNumber)) |
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.
how is stateId
a block root here? you need to pass the headroot here.
86a639c
to
fd5da7f
Compare
beacon-chain/rpc/eth/helpers/sync.go
Outdated
return true, errors.Wrapf(err, "could not get block roots for slot %d", st.Slot()) | ||
} | ||
if len(roots) == 0 { | ||
return false, errors.New("no blocks returned from the database") |
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.
better to return true here
beacon-chain/rpc/eth/helpers/sync.go
Outdated
for _, r := range roots { | ||
canonical, err := chainInfo.IsCanonical(ctx, r) | ||
if err != nil { | ||
return true, errors.Wrapf(err, "could not check canonical status") | ||
} | ||
if canonical { | ||
optimistic, err := optimisticModeFetcher.IsOptimistic(ctx) | ||
if err != nil { | ||
return true, errors.Wrap(err, "could not check optimistic status") | ||
} | ||
if !optimistic { | ||
return false, nil | ||
} | ||
finalizedSlot, err := slots.EpochStart(chainInfo.FinalizedCheckpt().Epoch) | ||
if err != nil { | ||
return true, errors.Wrap(err, "could not get head state's finalized slot") | ||
} | ||
if st.Slot() <= finalizedSlot { | ||
return false, nil | ||
} | ||
return true, nil | ||
} |
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.
This block does not check what you want. Suppose you get roots = [r1, r2]
with r1 canonical and r2 not, both past the finalized version. The node is not optimistic. In this situation you would return false
.
Now suppose that the block with root r2
has stateRoot
precisely the state you queried for. In this case you should have returned true
.
What you need to do here is to requests the blocks, not the roots. And then check if the stateRoot matches the given id, and in that case (only in that case) check if it is canonical or not, etc...
ff3a8bd
to
c6c866f
Compare
c6c866f
to
1a4b3ef
Compare
9527a83
to
289d164
Compare
289d164
to
1090deb
Compare
optimistic, err := optimisticModeFetcher.IsOptimistic(ctx) | ||
if err != nil { | ||
return true, errors.Wrap(err, "could not check optimistic status") | ||
} | ||
if !optimistic { | ||
return false, nil | ||
} |
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.
Why not move this to before strconv.ParseUint(stateIdString, 10, 64)
?
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.
Very smart check btw
beacon-chain/rpc/eth/helpers/sync.go
Outdated
r, err := chainInfo.ForkChoicer().AncestorRoot(ctx, bytesutil.ToBytes32(headRoot), primitives.Slot(slotNumber)) | ||
if err != nil { | ||
return true, errors.Wrap(err, "could not get ancestor root") | ||
} |
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.
This is very smart
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.
This is Potuz's idea
case "head": | ||
return optimisticModeFetcher.IsOptimistic(ctx) | ||
case "genesis", "finalized": | ||
return false, nil |
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.
Why wouldn't we check finalized?
fcp := chainInfo.FinalizedJustifiedCheckpoint()
if fcp == nil {
return true, errors.New("received nil finalized checkpoint")
}
return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(fcp.Root))
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.
finalized block (which corresponds to finalized state) can't be optimistic, as said on Slack
Blocked by #12162 |
What type of PR is this?
Optimization
What does this PR do? Why is it needed?
Several users complained about out-of-memory issues happening when issuing API requests. This is most likely because of how we check for optimistic status. Currently we calculate the state root every time inside
IsOptimistic
, which is very inefficient. In tghis PR we move to an algorithm which does not calculate HTR on the state. The algorithm was designed by @potuz