-
Notifications
You must be signed in to change notification settings - Fork 2k
multiply non-single execution spends by the number of participants #19666
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
Changes from all commits
ff21a79
78e514f
56bdc71
e3816fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,8 @@ type ProtoDetail struct { | |
| type ReportStep struct { | ||
| // The ID of the capability being used in this step | ||
| CapabilityID string | ||
| // CapDONN is the total number of nodes in a capability DON. | ||
| CapdonN uint32 | ||
| // The maximum amount of universal credits that should be used in this step | ||
| Deduction decimal.Decimal | ||
| // The actual resource spend that each node used for this step | ||
|
|
@@ -367,7 +369,7 @@ func (r *Report) Deduct(ref string, opt DeductOpt) ([]capabilities.SpendLimit, e | |
| // by returning earmarked local balance to the available to use pool and adding the spend to the metering report. | ||
| // The Deduct method must be called before Settle. | ||
| // We expect to only set this value once - an error is returned if a step would be overwritten. | ||
| func (r *Report) Settle(ref string, spendsByNode []capabilities.MeteringNodeDetail) error { | ||
| func (r *Report) Settle(ref string, metadata capabilities.ResponseMetadata) error { | ||
| r.mu.Lock() | ||
| defer r.mu.Unlock() | ||
|
|
||
|
|
@@ -388,7 +390,7 @@ func (r *Report) Settle(ref string, spendsByNode []capabilities.MeteringNodeDeta | |
| resourceSpends := make(map[string][]ReportStepDetail) | ||
|
|
||
| // Group by resource dimension | ||
| for _, nodeDetail := range spendsByNode { | ||
| for _, nodeDetail := range metadata.Metering { | ||
| resourceSpends[nodeDetail.SpendUnit] = append(resourceSpends[nodeDetail.SpendUnit], ReportStepDetail{ | ||
| Peer2PeerID: nodeDetail.Peer2PeerID, | ||
| SpendValue: nodeDetail.SpendValue, | ||
|
|
@@ -424,6 +426,10 @@ func (r *Report) Settle(ref string, spendsByNode []capabilities.MeteringNodeDeta | |
| } | ||
|
|
||
| deciVals = append(deciVals, value) | ||
|
|
||
| if isGasSpendType(unit) && len(deciVals) > 1 { | ||
| r.switchToMeteringMode(fmt.Errorf("multiple executions for single execution unit [%s]: %w", unit, err)) | ||
| } | ||
| } | ||
|
|
||
| // TODO: explicitly ignore RPC_EVM spend types for now - | ||
|
|
@@ -435,7 +441,20 @@ func (r *Report) Settle(ref string, spendsByNode []capabilities.MeteringNodeDeta | |
| } | ||
|
|
||
| aggregated.SpendValue = medianSpend(deciVals) | ||
| bal, err := r.balance.ConvertToBalance(unit, aggregated.SpendValue) | ||
| value := aggregated.SpendValue | ||
|
|
||
| // if N is not set, assume 1 | ||
| if metadata.CapDON_N == 0 { | ||
| metadata.CapDON_N = 1 | ||
| } | ||
|
|
||
| // TODO: indicate in the registry config that a capability is single execution or not | ||
| // https://smartcontract-it.atlassian.net/browse/CRE-1037 | ||
| if !isGasSpendType(unit) { | ||
| value = value.Mul(decimal.NewFromUint64(uint64(metadata.CapDON_N))) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we cast to uint32 prior, now uint64 here - should the type in the proto be set to the equivalent of a unit64 to streamline all these conversions?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Many of the libraries in Go tend to use the 64 bit variants. It might make sense to streamline as 64 bit if memory size isn't an issue. |
||
| } | ||
|
|
||
| bal, err := r.balance.ConvertToBalance(unit, value) | ||
|
|
||
| if err != nil { | ||
| r.switchToMeteringMode(fmt.Errorf("attempted to Settle [%s]: %w", unit, err)) | ||
|
|
@@ -448,6 +467,7 @@ func (r *Report) Settle(ref string, spendsByNode []capabilities.MeteringNodeDeta | |
| } | ||
|
|
||
| step.Spends = resourceSpends | ||
| step.CapdonN = metadata.CapDON_N | ||
| r.steps[ref] = step | ||
|
|
||
| // if in metering mode, exit early without modifying local balance | ||
|
|
@@ -508,7 +528,20 @@ func (r *Report) FormatReport() *protoEvents.MeteringReport { | |
| nodeDetails := []*protoEvents.MeteringReportNodeDetail{} | ||
| r.stepRefLookup = append(r.stepRefLookup, ref+":"+step.CapabilityID) | ||
|
|
||
| for unit, details := range step.Spends { | ||
| // since map key order is non-deterministic, order the keys tohelp make tests deterministic | ||
| // until per-unit aggregation is fixed | ||
| orderedUnits := make([]string, 0, len(step.Spends)) | ||
| for unit := range step.Spends { | ||
| orderedUnits = append(orderedUnits, unit) | ||
| } | ||
|
|
||
| sort.Slice(orderedUnits, func(i, j int) bool { | ||
| return orderedUnits[i] > orderedUnits[j] | ||
| }) | ||
|
|
||
| for _, unit := range orderedUnits { | ||
| details := step.Spends[unit] | ||
|
|
||
| for _, detail := range details { | ||
| nodeDetails = append(nodeDetails, &protoEvents.MeteringReportNodeDetail{ | ||
| Peer_2PeerId: detail.Peer2PeerID, | ||
|
|
@@ -526,6 +559,7 @@ func (r *Report) FormatReport() *protoEvents.MeteringReport { | |
| } | ||
|
|
||
| stepDetails.Nodes = nodeDetails | ||
| stepDetails.CapdonN = step.CapdonN | ||
| protoReport.Steps[ref] = stepDetails | ||
| } | ||
|
|
||
|
|
||
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.
/nit add ticket num where we handle this more flexibly by injecting whether or not its a single execution cap into the wf registry config?