-
Notifications
You must be signed in to change notification settings - Fork 14
x/core with core features #585
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
base: main
Are you sure you want to change the base?
Conversation
d797d07
to
06b662d
Compare
Oops, thought I fixed all interchain test fails, but I see there is one still failing. Looking into it now.. |
444f094
to
1716ec1
Compare
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.
Taking a break for now so I give this PR the attention to detail it deserves
if err != nil { | ||
telemetry.SetGauge(1, types.TelemetryKeyDRFlowHalt) | ||
k.Logger(ctx).Error("[HALTS_DR_FLOW] failed to retrieve data request", "err", err) | ||
return 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.
can this ever happen now that it's also stored in the module? Or ig we still have the shim right so it remains for a while?
x/core/keeper/endblock.go
Outdated
return err | ||
} | ||
|
||
err = k.UpdateDataRequestIndexing(ctx, dr.Index(), dr.Status, types.DATA_REQUEST_STATUS_UNSPECIFIED) | ||
if err != nil { | ||
return err | ||
} | ||
dr.Status = types.DATA_REQUEST_STATUS_UNSPECIFIED | ||
|
||
err = k.RemoveRevealBodies(ctx, dr.Id) | ||
if err != nil { | ||
return err | ||
} | ||
err = k.RemoveDataRequest(ctx, dr.Id) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
dataResults[i].GasUsed = gasMeter.TotalGasUsed() | ||
dataResults[i].Id, err = dataResults[i].TryHash() | ||
if err != nil { | ||
return err |
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.
these errors would full exit the processing... is that what we want? Not sure how chain side handled it before. The contract side only errored when it couldn't load the staking config, escrow, staaker or failed to set the response
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.
For crucial errors like state write errors or hashing errors, we returned an error to halt the chain. If the contract returned an error, we caught the error without halting the chain.
Once we add pausability, we could also pause data request when a serious, unexpected error like this is encountered?
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.
That's a good food for thought question. I'm not sure if we'd want to automatically do that, but there's merit in it too. Hmm
x/core/keeper/endblock.go
Outdated
|
||
// Phase 1: Filtering | ||
//nolint:gosec // G115: No overflow guaranteed by validation logic. | ||
filterResult, filterErr := ExecuteFilter(reveals, dr.ConsensusFilter, uint16(dr.ReplicationFactor), params, gasMeter) |
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.
Oh I would prefer we don't cast fields every time we use them, and I assume we do the same for other similar fields. Is it painful to have the Protobuf struct have a validation method that would then ensure correct types?
x/core/keeper/endblock.go
Outdated
StdOut []string | ||
StdErr []string | ||
Result []byte | ||
ExitCode uint32 |
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.
Ideally a uint8
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.
The VM returns a uint32 value, so I think we should keep it until we change it from the VM side?
59f7878
to
206282d
Compare
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.
Next batch of review comments.
x/core/keeper/gas_meter.go
Outdated
return dists | ||
} | ||
|
||
func (k Keeper) ProcessDistributions(ctx sdk.Context, dists []types.Distribution, dr *types.DataRequest, minimumStake math.Int) error { |
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.
Considering in endblock.go
in the same module we call GetGasMeterResults
and then immediately call this function- it would seem we can just merge them? I.e. no need to build the distribution list in the first place. Or do we ever plan to have logic in-between those two steps?
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.
Yeah we could. It was just making testing difficult because it is difficult to check the distribution amounts.
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 think it would be worth merging them, maybe we can make some test utilities to make testing that flow easier.
amount = math.MinInt(dist.DataProxyReward.Amount, remainingEscrow) | ||
payoutAddr, err := sdk.AccAddressFromBech32(dist.DataProxyReward.PayoutAddress) | ||
if err != nil { | ||
// Should not be reachable because the address has been validated. |
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 know we aren't doing this in this PR. But maybe a log that says unreachable and reason. This way if it ever pops up in the logs we can appropiately panic lol
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.
Well the validate function of data proxy registration msg does already verify that the payout address is valid.
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.
Yeee, just saying we should have a log statement that says unreachable- more as a paranoia thing than anything else.
amount = math.MinInt(dist.ExecutorReward.Amount, remainingEscrow) | ||
staker, err := k.GetStaker(ctx, dist.ExecutorReward.Identity) | ||
if err != nil { | ||
return err |
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.
The contract did not error in this case. IT would simply emit an error event and move on to the next iteration of the loop. The return statement would instead exit the function early not doing the payouts at all.
Or is this another unreachable situation due to earlier checks? Or can executors ever unregister so their proxy no longer exists?
TLDR this is a change from the contract.
} | ||
|
||
remainingEscrow = remainingEscrow.Sub(amount) | ||
} |
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 should be cautious with the errors in this loop. The contract would never error in this loop and instead would skip over the distrubtion and move on to the next one. The returns here, if I understand correctly, would cause this not to happen.
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.
Though I think when we copy more of the tests over from the contract any issues here should be caught
drID, err := msg.MsgHash() | ||
if err != nil { | ||
return nil, err | ||
} | ||
exists, err := m.HasDataRequest(ctx, drID) |
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.
Difference from contract here- The hash function on contract returns a [u8; 32]
and the map stores them by that not the hex string. Which I commented on the keeper why we would prefer this.
stakers collections.Map[string, types.Staker] | ||
|
||
// Data request-related states: | ||
// dataRequests is a map of data request IDs to data request objects. | ||
dataRequests collections.Map[string, types.DataRequest] |
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.
So far looking at these, this is a change, we stored these by a enforced length of u8
arrays. The reason being this data structure under the hood convertes the Keys to a byte array anyways. So we are going from byte array -> hex string -> byte array again which is wasteful.
Maybe some of the other collcetions are using string
keys where they should be byte arrays as well no sure. Going through as I go through.
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.
Yeah I think you're right. Will try changing the data request ID to bytes
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.
if err != nil { | ||
return nil, err | ||
} | ||
publicKey, err := hex.DecodeString(msg.PublicKey) |
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 should be using the byte array version to check/update see the comment on the keeper to see the rationale there.
Escrow: msg.Funds.Amount, | ||
TimeoutHeight: ctx.BlockHeight() + int64(drConfig.CommitTimeoutInBlocks), |
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'm still unsure if these should be attached here or not. I think we can leave it for now but we should do the gas calculation stuff again to see if it improved/worsened things.
240a2a7
to
7f9067a
Compare
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.
Good job HY!
// Verify against the stored commit. | ||
expectedCommit, err := msg.RevealHash() | ||
if err != nil { | ||
return nil, err | ||
} | ||
if !bytes.Equal(commit, expectedCommit) { | ||
return nil, types.ErrRevealMismatch | ||
} |
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.
Let's move this check to before the msg.Valdiate
call, checking this is cheaper than checking possibly a large amount of proxy public keys. So better to get this check out of the way first and fail the commit sooner than checking all of those then failing.
func (k Keeper) GetStakersCount(ctx sdk.Context) (uint32, error) { | ||
count := uint32(0) | ||
err := k.stakers.Walk(ctx, nil, func(_ string, _ types.Staker) (stop bool, err error) { | ||
count++ | ||
return false, nil | ||
}) | ||
return count, err | ||
} |
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 should definitely modify the stakers on the keeper struct to have a count so we don't have to iterate it every time. It's okay-ish for while things are allowlisted, but definitely not for when we turn that off.
dr, err := k.GetDataRequest(ctx, drID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = k.UpdateDataRequestIndexing(ctx, dr.Index(), dr.Status, types.DATA_REQUEST_STATUS_TALLYING) |
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 do think this is a drawback of storing the status on the Data Request itself. We have to get the data request as well everytime instead of just updating a Status map.
if !semver.IsValid("v"+m.Version) || semver.Prerelease("v"+m.Version) != "" || semver.Build("v"+m.Version) != "" { | ||
return ErrInvalidVersion.Wrapf("%s", m.Version) | ||
} |
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 don't remember if we need to do this in multiple places- but if we do could be a good ideal to pull this into a separate function and re-use it
return nil | ||
} | ||
|
||
func (dc *DataRequestConfig) Validate() error { |
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.
Ah can ingnore my earlier comment about NonZero stuff I hadn't seen this yet
- Also leaves out outdated integration test files for now: endblock_fuzz_test.go and most of endblock_test.go.
- Rename some field names for clarity. - Use methods instead of direct access to collections. - Improve comments. - Improve PostDataRequest message validation. Add relevant tests.
- Change block height types to int64, except for hashing - Lint
- Fixes a bug where status transition from committing to tallying was not considered as a possibility. - Committing, revealing, and tallying are combined into a single collection with different prefixes. - DataRequestStatus enum type now follows proto3 requirements. - Invalid status transition is now identified as an error in UpdateDataRequestIndexing. - DataRequest's TimeoutHeight is set to -1 if it is not in timeout queue.
- Stop distribution if data request escrow runs out. - RevealBody.Reveal is now a byte slice instead of a base64 string. - Core EndBlock now completes the full tally process of a given data request in one loop iteration. - Validate that a reveal's exit code can fit in a uint8. - Validate version in PostDataRequest. - Basic module parameter validation
004b29f
to
d4e6efc
Compare
I will split up this PR and open new ones since this is getting way too long. I will keep this in draft and make sure to address @gluax 's comments. |
Explanation of Changes
Implementation of x/core with full data request flow.
AddToAllowList
(may not be necessary),Stake
,PostDataRequest
,CommitDataResult
, andRevealDataResult
.States
Messages
Owner
Staking
Data Requests
Testing
(Write your test plan here)
Dependency Chain
Think about the changes (msgs, events, limits, etc.) made in this PR and see if you need to make an issue or a PR on the following repos.
Related PRs and Issues
Closes #587