-
Notifications
You must be signed in to change notification settings - Fork 228
optimistic sig share creation for managed keys #7831
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
573aef0
faebd8f
4800fee
170d42a
7b76320
4bbc8ea
ab81017
f88f1e5
fb7b9b7
40875b5
197b42d
d20fca5
7faae14
099ce93
1ee6f23
735f94d
cd91661
5de6697
d195344
3b23668
832a01c
e4d6eb1
da0c4b2
56ee618
f20cfd2
7628f43
0f74004
490ad26
2cea8d5
6563f97
4467501
829d267
58fa573
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 |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package v2 | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "time" | ||
|
|
||
| "github.com/multiversx/mx-chain-core-go/core" | ||
| "github.com/multiversx/mx-chain-go/consensus/spos" | ||
| ) | ||
|
|
||
| func checkGoRoutinesThrottler( | ||
| ctx context.Context, | ||
| signatureThrottler core.Throttler, | ||
| ) error { | ||
| for { | ||
| if signatureThrottler.CanProcess() { | ||
| break | ||
| } | ||
|
|
||
| select { | ||
| case <-time.After(timeSpentBetweenChecks): | ||
| continue | ||
| case <-ctx.Done(): | ||
| return fmt.Errorf("%w while checking the throttler", spos.ErrTimeIsOut) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,11 @@ import ( | |
| "github.com/multiversx/mx-chain-go/process/asyncExecution/cache" | ||
| ) | ||
|
|
||
| type consensusPubKey struct { | ||
| idx int | ||
| pkBytes []byte | ||
| } | ||
|
|
||
| // maxAllowedSizeInBytes defines how many bytes are allowed as payload in a message | ||
| const maxAllowedSizeInBytes = uint32(core.MegabyteSize * 95 / 100) | ||
|
|
||
|
|
@@ -29,6 +34,7 @@ type subroundBlock struct { | |
| worker spos.WorkerHandler | ||
| mutBlockProcessing sync.Mutex | ||
| syncController spos.NtpSyncControllerHandler | ||
| signatureThrottler core.Throttler | ||
| } | ||
|
|
||
| // NewSubroundBlock creates a subroundBlock object | ||
|
|
@@ -37,6 +43,7 @@ func NewSubroundBlock( | |
| processingThresholdPercentage int, | ||
| worker spos.WorkerHandler, | ||
| syncController spos.NtpSyncControllerHandler, | ||
| signatureThrottler core.Throttler, | ||
| ) (*subroundBlock, error) { | ||
| err := checkNewSubroundBlockParams(baseSubround) | ||
| if err != nil { | ||
|
|
@@ -49,12 +56,16 @@ func NewSubroundBlock( | |
| if check.IfNil(syncController) { | ||
| return nil, ErrNilRoundSyncController | ||
| } | ||
| if check.IfNil(signatureThrottler) { | ||
| return nil, spos.ErrNilThrottler | ||
| } | ||
|
|
||
| srBlock := subroundBlock{ | ||
| Subround: baseSubround, | ||
| processingThresholdPercentage: processingThresholdPercentage, | ||
| worker: worker, | ||
| syncController: syncController, | ||
| signatureThrottler: signatureThrottler, | ||
| } | ||
|
|
||
| srBlock.Job = srBlock.doBlockJob | ||
|
|
@@ -142,7 +153,7 @@ func (sr *subroundBlock) doBlockJob(ctx context.Context) bool { | |
| return false | ||
| } | ||
|
|
||
| sentWithSuccess := sr.sendBlock(header, body, leader) | ||
| sentWithSuccess := sr.sendBlock(ctx, header, body, leader) | ||
| if !sentWithSuccess { | ||
| return false | ||
| } | ||
|
|
@@ -220,7 +231,12 @@ func printLogMessage(ctx context.Context, baseMessage string, err error) { | |
| log.Debug(baseMessage, "error", err.Error()) | ||
| } | ||
|
|
||
| func (sr *subroundBlock) sendBlock(header data.HeaderHandler, body data.BodyHandler, leader string) bool { | ||
| func (sr *subroundBlock) sendBlock( | ||
| ctx context.Context, | ||
| header data.HeaderHandler, | ||
| body data.BodyHandler, | ||
| leader string, | ||
| ) bool { | ||
| marshalledBody, err := sr.Marshalizer().Marshal(body) | ||
| if err != nil { | ||
| log.Debug("sendBlock.Marshal: body", "error", err.Error()) | ||
|
|
@@ -236,7 +252,7 @@ func (sr *subroundBlock) sendBlock(header data.HeaderHandler, body data.BodyHand | |
| sr.logBlockSize(marshalledBody, marshalledHeader) | ||
| headerHash := sr.Hasher().Compute(string(marshalledHeader)) | ||
|
|
||
| if !sr.sendBlockBody(body, marshalledBody) || !sr.sendBlockHeader(header, headerHash) { | ||
| if !sr.sendBlockBody(body, marshalledBody) || !sr.sendBlockHeader(ctx, header, headerHash) { | ||
| return false | ||
| } | ||
|
|
||
|
|
@@ -313,6 +329,7 @@ func (sr *subroundBlock) sendBlockBody( | |
|
|
||
| // sendBlockHeader method sends the proposed block header in the subround Block | ||
| func (sr *subroundBlock) sendBlockHeader( | ||
| ctx context.Context, | ||
| headerHandler data.HeaderHandler, | ||
| headerHash []byte, | ||
| ) bool { | ||
|
|
@@ -336,6 +353,8 @@ func (sr *subroundBlock) sendBlockHeader( | |
| sr.SetData(headerHash) | ||
| sr.SetHeader(headerHandler) | ||
|
|
||
| sr.triggerCreateSignaturesForManagedKeys(ctx, headerHash, headerHandler) | ||
|
|
||
| // log the header output for debugging purposes | ||
| headerOutput, err := common.PrettifyStruct(headerHandler) | ||
| if err == nil { | ||
|
|
@@ -345,6 +364,100 @@ func (sr *subroundBlock) sendBlockHeader( | |
| return true | ||
| } | ||
|
|
||
| func (sr *subroundBlock) triggerCreateSignaturesForManagedKeys( | ||
| ctx context.Context, | ||
| headerHash []byte, | ||
| headerHandler data.HeaderHandler, | ||
| ) { | ||
| if check.IfNil(headerHandler) { | ||
| log.Debug("triggerCreateSignaturesForManagedKeys: triggered with nil header") | ||
| return | ||
| } | ||
|
|
||
| if sr.RoundHandler().Index() != int64(headerHandler.GetRound()) { | ||
| log.Debug("triggerCreateSignaturesForManagedKeys: not for current round", | ||
| "currentRound", sr.RoundHandler().Index(), | ||
| "headerRound", headerHandler.GetRound(), | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| currentEpoch := headerHandler.GetEpoch() | ||
|
|
||
| sigSubroundEndTime := time.Duration(float64(sr.RoundHandler().TimeDuration()) * srSignatureEndTime) | ||
| timeLeft := sr.RoundHandler().RemainingTime(sr.RoundHandler().TimeStamp(), sigSubroundEndTime) | ||
| sigCtx, cancel := context.WithTimeout(ctx, timeLeft) | ||
| sr.SetSignaturesCtxCancelFunc(cancel) | ||
|
|
||
| keys := sr.getManagedKeysByIndex() | ||
| if len(keys) == 0 { | ||
| return | ||
| } | ||
|
|
||
| wg := sr.SignaturesWaitGroup() | ||
| wg.Add(len(keys)) | ||
|
|
||
| go func() { | ||
|
Collaborator
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. is this needed?
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. yes, that was the intention, to trigger asynchronously, due to goroutines throttler which might block on limit reached |
||
| triggered := 0 | ||
| for _, pk := range keys { | ||
| err := checkGoRoutinesThrottler(sigCtx, sr.signatureThrottler) | ||
| if err != nil { | ||
| log.Debug("triggerCreateSignaturesForManagedKeys.checkGoRoutinesThrottler", "err", err) | ||
| cancel() | ||
|
AdoAdoAdo marked this conversation as resolved.
|
||
|
|
||
| for i := triggered; i < len(keys); i++ { | ||
| wg.Done() | ||
| } | ||
|
|
||
| return | ||
| } | ||
| sr.signatureThrottler.StartProcessing() | ||
|
|
||
| triggered++ | ||
|
|
||
| go func(sigCtx context.Context, idx int, pkBytes []byte) { | ||
| defer sr.signatureThrottler.EndProcessing() | ||
| defer wg.Done() | ||
|
|
||
| select { | ||
| case <-sigCtx.Done(): | ||
| log.Info("triggerCreateSignaturesForManagedKeys: context done", "timeLeft", timeLeft) | ||
| return | ||
| default: | ||
| } | ||
|
|
||
| _, err := sr.SigningHandler().CreateSignatureShareForPublicKey( | ||
| sigCtx, | ||
| headerHash, | ||
| uint16(idx), | ||
| currentEpoch, | ||
| pkBytes, | ||
| ) | ||
| if err != nil { | ||
| log.Info("triggerCreateSignaturesForManagedKeys.CreateSignatureShareForPublicKey", "error", err.Error()) | ||
| return | ||
| } | ||
| }(sigCtx, pk.idx, pk.pkBytes) | ||
| } | ||
| }() | ||
|
|
||
| log.Debug("step 1: multi keys signatures creation has been triggered", "num", len(keys)) | ||
|
Collaborator
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. perhaps call cancel()?
Collaborator
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. or call it on defer after creation
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. the context was set to be cancelled on signature subround, after waiting with timeout, here we are just triggering the creation |
||
| } | ||
|
|
||
| func (sr *subroundBlock) getManagedKeysByIndex() []consensusPubKey { | ||
| keys := make([]consensusPubKey, 0) | ||
| for idx, pk := range sr.ConsensusGroup() { | ||
| pkBytes := []byte(pk) | ||
| if !sr.IsKeyManagedBySelf(pkBytes) { | ||
| continue | ||
| } | ||
|
|
||
| keys = append(keys, consensusPubKey{idx: idx, pkBytes: pkBytes}) | ||
| } | ||
|
|
||
| return keys | ||
| } | ||
|
|
||
| func (sr *subroundBlock) sendDirectSentTransactions( | ||
| header data.HeaderHandler, | ||
| body data.BodyHandler, | ||
|
|
@@ -643,6 +756,8 @@ func (sr *subroundBlock) receivedBlockHeader(headerHandler data.HeaderHandler) { | |
|
|
||
| sr.AddReceivedHeader(headerHandler) | ||
|
|
||
| sr.triggerCreateSignaturesForManagedKeys(context.Background(), headerHash, headerHandler) | ||
|
|
||
| ctx, cancel := context.WithTimeout(context.Background(), sr.RoundHandler().TimeDuration()) | ||
| defer cancel() | ||
|
|
||
|
|
||
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.
also if triggered on a goroutine, maybe check that the round on the header is still the round in the RoundHandler, otherwise exit without triggering signing.
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.
done