Пример #1
0
        private async Task HandleSingleHackAsync(IEnumerable <ActorInfo> actors, HackStatus hack, JudgeStatus judge, Problem problem, Guid?testCaseId, CancellationToken token)
        {
            var sub       = new SubJudgeStatus();
            var isBadData = false;

            if (actors.Count(x => x.Name == "CompareActor") == 0)
            {
                var rangeValidateActor = actors.FirstOrDefault(x => x.Stage == "ValidateData");
                var rangeRunner        = rangeValidateActor == null ? null : await _mgmt.ReadBlobAsObjectAsync <Runner>(rangeValidateActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                var runActor  = actors.FirstOrDefault(x => x.Stage == "GenerateHackeeAnswer");
                var runRunner = runActor == null ? null : await _mgmt.ReadBlobAsObjectAsync <Runner>(runActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                if (rangeRunner != null && rangeRunner.ExitCode != 0)
                {
                    isBadData            = true;
                    sub.TimeUsedInMs     = 0;
                    sub.MemoryUsedInByte = 0;
                    sub.Result           = JudgeResult.Accepted;
                    sub.Hint             = string.Join(Environment.NewLine, rangeValidateActor.Exceptions) + Environment.NewLine + rangeRunner.Error;
                }
                else if (runRunner.IsTimeout)
                {
                    sub.TimeUsedInMs     = problem.TimeLimitationPerCaseInMs;
                    sub.MemoryUsedInByte = runRunner.PeakMemory;
                    sub.Result           = JudgeResult.TimeExceeded;
                    sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runRunner.Error;
                }
                else if (runRunner.ExitCode == 139 || runActor.Exceptions.Any(x => x.Contains("May cause by out of memory")) || runRunner.Error.Contains("std::bad_alloc") || runRunner.PeakMemory > problem.MemoryLimitationPerCaseInByte)
                {
                    sub.TimeUsedInMs     = runRunner.UserTime;
                    sub.MemoryUsedInByte = problem.MemoryLimitationPerCaseInByte;
                    sub.Result           = JudgeResult.MemoryExceeded;
                    sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runRunner.Error;
                }
                else if (runRunner.ExitCode != 0)
                {
                    sub.TimeUsedInMs     = runRunner.UserTime;
                    sub.MemoryUsedInByte = runRunner.PeakMemory;
                    sub.Result           = JudgeResult.RuntimeError;
                    sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runRunner.Error + Environment.NewLine + $"User process exited with code { runRunner.ExitCode }";
                }
            }
            else if (actors.Count(x => x.Name == "CompareActor") > 0)
            {
                var runners       = actors.Where(x => x.Name == "CompareActor").Select(x => x.Outputs.Single(y => y.Name == "runner.json"));
                var runnerResults = runners.Select(x => _mgmt.ReadBlobAsObjectAsync <Runner>(x.Id, token).Result);
                var exitCodes     = runnerResults.Select(x => x.ExitCode);
                if (exitCodes.Distinct().Count() > 1)
                {
                    isBadData = true;
                }
                else
                {
                    var runActor  = actors.First(x => x.Stage == "GenerateHackeeAnswer");
                    var runRunner = await _mgmt.ReadBlobAsObjectAsync <Runner>(runActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                    var compareActor = actors.Last(x => x.Name == "CompareActor");
                    var runner       = await _mgmt.ReadBlobAsObjectAsync <Runner>(compareActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                    if (runner.ExitCode < 0 || runner.ExitCode > 2)
                    {
                        sub.TimeUsedInMs     = 0;
                        sub.MemoryUsedInByte = 0;
                        sub.Result           = JudgeResult.SystemError;
                        sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runner.Error;
                    }
                    else
                    {
                        var validatorOutput = Encoding.UTF8.GetString((await _mgmt.GetBlobAsync(compareActor.Outputs.Single(x => x.Name == "stdout.txt").Id)).Body);
                        sub.TimeUsedInMs     = runRunner.UserTime;
                        sub.MemoryUsedInByte = runRunner.PeakMemory;
                        sub.Result           = (JudgeResult)runner.ExitCode;
                        sub.Hint             = validatorOutput + Environment.NewLine + string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runner.Error;
                    }
                }
            }
            else
            {
                isBadData = true;
            }

            if (hack == null && actors.Count(x => x.Stage == "GenerateHackeeAnswer") > 0 && testCaseId.HasValue)
            {
                var runActor = actors.First(x => x.Stage == "GenerateHackeeAnswer");
                var statusId = Guid.Parse(runActor.Tag);
                var testCase = await _db.TestCases.SingleAsync(x => x.Id == testCaseId.Value, token);

                var testCases = await _db.TestCases
                                .Where(x => x.ProblemId == problem.Id)
                                .Select(x => x.Id)
                                .ToListAsync(token);

                var status = await _db.JudgeStatuses
                             .Include(x => x.SubStatuses)
                             .SingleAsync(x => x.Id == statusId, token);

                sub.StatusId     = statusId;
                sub.TestCaseId   = testCaseId.Value;
                sub.InputBlobId  = testCase.InputBlobId;
                sub.OutputBlobId = testCase.OutputBlobId;
                sub.SubId        = testCases.IndexOf(testCaseId.Value);
                status.SubStatuses.Add(sub);
                status.MemoryUsedInByte = status.SubStatuses.Max(x => x.MemoryUsedInByte);
                status.TimeUsedInMs     = status.SubStatuses.Sum(x => x.TimeUsedInMs);
                status.Result           = status.SubStatuses.Max(x => x.Result);
                _db.SaveChanges();
            }

            if (hack != null)
            {
                _db.HackStatuses
                .Where(x => x.Id == hack.Id)
                .SetField(x => x.HackeeResult).WithValue(isBadData ? JudgeResult.Accepted : sub.Result)
                .SetField(x => x.TimeUsedInMs).WithValue(sub.TimeUsedInMs)
                .SetField(x => x.MemoryUsedInByte).WithValue(sub.MemoryUsedInByte)
                .SetField(x => x.Result).WithValue(isBadData ? (HackResult.BadData) : (sub.Result == JudgeResult.Accepted ? HackResult.Failed : HackResult.Succeeded))
                .SetField(x => x.Hint).WithValue(sub.Hint)
                .Update();
            }
        }
        public override void OnHackCompleted(HackStatus status)
        {
            if (status.Result == HackResult.Succeeded)
            {
                // 1. Set the status to be non-hackable
                DB.ContestProblemLastStatuses
                .Where(x => x.StatusId == status.JudgeStatusId && x.ContestId == ContestId)
                .SetField(x => x.IsHackable).WithValue(false)
                .SetField(x => x.IsHacked).WithValue(true)
                .Update();

                // 2. Add the hack data to problem
                var input           = status.HackDataBlobId.Value;
                var testCase        = DB.TestCases.FirstOrDefault(x => x.InputBlobId == input && x.ProblemId == status.Status.ProblemId);
                var testCaseExisted = testCase != null;
                if (!testCaseExisted)
                {
                    var inputLength  = ManagementService.GetBlobAsync(input).Result.Body.Length;
                    var stateMachine = ManagementService.GetStateMachineInstanceAsync(status.RelatedStateMachineIds.Last().StateMachineId).Result;
                    var output       = stateMachine.StartedActors.First(x => x.Tag == "Standard").Outputs.First(x => x.Name == "stdout.txt").Id;
                    var outputLength = ManagementService.GetBlobAsync(output).Result.Body.Length;

                    testCase = new TestCase
                    {
                        ContestId        = ContestId,
                        InputBlobId      = input,
                        InputSizeInByte  = inputLength,
                        OutputBlobId     = output,
                        OutputSizeInByte = outputLength,
                        ProblemId        = status.Status.ProblemId,
                        Type             = TestCaseType.Hack
                    };
                    DB.TestCases.Add(testCase);
                    DB.SaveChanges();
                }

                // 3. Add the result into sub judge status
                if (!testCaseExisted)
                {
                    var sub = new SubJudgeStatus
                    {
                        SubId            = DB.SubJudgeStatuses.Where(x => x.StatusId == status.JudgeStatusId).Count(),
                        Hint             = status.Hint,
                        MemoryUsedInByte = status.MemoryUsedInByte,
                        TimeUsedInMs     = status.TimeUsedInMs,
                        Result           = status.HackeeResult,
                        InputBlobId      = testCase.InputBlobId,
                        OutputBlobId     = testCase.OutputBlobId,
                        TestCaseId       = testCase.Id,
                        StatusId         = status.JudgeStatusId
                    };
                    DB.SubJudgeStatuses.Add(sub);
                    DB.SaveChanges();
                }

                // 4. Add point for the hacker
                DB.ContestProblemLastStatuses
                .Where(x => x.ContestId == ContestId && x.ProblemId == status.Status.ProblemId && x.UserId == status.UserId)
                .SetField(x => x.Point2).Plus(1)
                .Update();

                // 5. Hack all statuses
                if (!testCaseExisted && DB.Attendees.Any(x => x.ContestId == ContestId && x.UserId == status.UserId && !x.IsVirtual))
                {
                    var affectedStatuses = DB.ContestProblemLastStatuses
                                           .Include(x => x.Status)
                                           .Where(x => x.ProblemId == status.Status.ProblemId && x.ContestId == ContestId && x.Status.BinaryBlobId.HasValue && x.IsAccepted)
                                           .ToList();

                    var problem     = DB.Problems.Single(x => x.Id == status.Status.ProblemId);
                    var validatorId = problem.ValidatorBlobId.HasValue ? problem.ValidatorBlobId.Value : Guid.Parse(Configuration["JoyOI:StandardValidatorBlobId"]);

                    var blobs = new List <BlobInfo>(affectedStatuses.Count + 10);
                    blobs.Add(new BlobInfo
                    {
                        Id = ManagementService.PutBlobAsync("limit.json", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new
                        {
                            UserTime     = status.Status.Problem.TimeLimitationPerCaseInMs,
                            PhysicalTime = status.Status.Problem.TimeLimitationPerCaseInMs * 4,
                            Memory       = status.Status.Problem.MemoryLimitationPerCaseInByte
                        }))).Result,
                        Name = "limit.json",
                        Tag  = "Problem=" + status.Status.ProblemId
                    });
                    blobs.Add(new BlobInfo(validatorId, problem.ValidatorBlobId.HasValue ? "Validator" + Constants.GetBinaryExtension(problem.ValidatorLanguage) : "Validator.out"));
                    blobs.Add(new BlobInfo(status.HackDataBlobId.Value, "data.txt", testCase.Id.ToString()));
                    blobs.Add(new BlobInfo(testCase.OutputBlobId, "std.txt", testCase.Id.ToString()));
                    foreach (var x in affectedStatuses)
                    {
                        blobs.Add(new BlobInfo(x.Status.BinaryBlobId.Value, "Hackee" + Constants.GetBinaryExtension(x.Status.Language), x.StatusId.ToString()));
                    }

                    ManagementService.PutStateMachineInstanceAsync("HackAllStateMachine", Configuration["ManagementService:CallBack"], blobs, 2);
                }
            }
            else if (status.Result == HackResult.Failed)
            {
                DB.ContestProblemLastStatuses
                .Where(x => x.ContestId == ContestId && x.ProblemId == status.Status.ProblemId && x.UserId == status.UserId)
                .SetField(x => x.Point2).Subtract(1)
                .SetField(x => x.Point3).Plus(1)
                .Update();
            }
        }