Add gas payment to initial execution and replayComputeState

Description

This PR https://github.com/rchain/rchain/pull/2385 added balance verification and gas payments to the `computeState` function of RuntimeManager.

Next, we need to update `replayComputeState` to verify the result of the balance check and to replay the gas payment.

The source code for my first attempt is below.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 def doReplayEval( start: Blake2b256Hash, processedDeploys: Seq[InternalProcessedDeploy] ): F[Either[(Option[DeployData], Failed), StateHash]] = Concurrent[F].defer { processedDeploys match { case InternalProcessedDeploy(deploy, deployCost, deployLog, paymentLog, deployStatus) :: rem => import deploy._ runtime.space.reset(start) *> { runtime.replaySpace.reset(start) *> { computeBalance(runtime)(deployer) >>= { balance => runtime.space.reset(start) *> { if (balance >= phloLimit * phloPrice) { replayComputeEffect(runtime, start)(deploy, deployLog) >>= { // TODO: Verify deploy cost == replay cost. case EvaluateResult(_, replayErrors) => DeployStatus.fromErrors(replayErrors) match { case internalErrors: InternalErrors => (deploy.some, internalErrors.asInstanceOf[Failed]) .asLeft[StateHash] .pure[F] case replayStatus: DeployStatus => if (deployStatus.isFailed != replayStatus.isFailed) ( deploy.some, ReplayStatusMismatch(replayStatus, deployStatus) .asInstanceOf[Failed] ).asLeft[StateHash].pure[F] else if (replayErrors.nonEmpty) { runtime.replaySpace.reset(start) *> { replayComputeEffect(runtime, start)( ConstructDeploy .sourceDeployNow( deployPaymentSource(phloPrice * deployCost.cost) ) .withDeployer(deployer), paymentLog ) *> runtime.replaySpace.createCheckpoint().attempt >>= { case Right(deployPaymentCheckpoint) => doReplayEval(deployPaymentCheckpoint.root, rem) case Left(ex: ReplayException) => (none[DeployData], UnusedCommEvent(ex).asInstanceOf[Failed]) .asLeft[StateHash] .pure[F] case Left(ex) => ( none[DeployData], UserErrors(Vector(ex)).asInstanceOf[Failed] ).asLeft[StateHash] .pure[F] } } } else runtime.replaySpace.createCheckpoint().attempt >>= { case Right(deployReplayCheckpoint) => replayComputeEffect(runtime, deployReplayCheckpoint.root)( ConstructDeploy .sourceDeployNow( deployPaymentSource(phloPrice * deployCost.cost) ) .withDeployer(deployer), paymentLog ) *> runtime.replaySpace.createCheckpoint().attempt >>= { case Right(deployPaymentCheckpoint) => doReplayEval(deployPaymentCheckpoint.root, rem) case Left(ex: ReplayException) => (none[DeployData], UnusedCommEvent(ex).asInstanceOf[Failed]) .asLeft[StateHash] .pure[F] case Left(ex) => ( none[DeployData], UserErrors(Vector(ex)).asInstanceOf[Failed] ).asLeft[StateHash] .pure[F] } case Left(ex: ReplayException) => (none[DeployData], UnusedCommEvent(ex).asInstanceOf[Failed]) .asLeft[StateHash] .pure[F] case Left(ex) => (none[DeployData], UserErrors(Vector(ex)).asInstanceOf[Failed]) .asLeft[StateHash] .pure[F] } } } } else deployStatus match { case UserErrors(Vector(InsufficientRevError(required, actual))) if required == phloLimit * phloPrice && actual == balance && deployLog.isEmpty && paymentLog.isEmpty && deployCost.cost == 0 => doReplayEval(start, rem) case _ => ( deploy.some, ReplayStatusMismatch( UserErrors( Vector(InsufficientRevError(phloLimit * phloPrice, balance)) ), deployStatus ).asInstanceOf[Failed] ).asLeft[StateHash].pure[F] } } } } } case _ => ByteString.copyFrom(start.bytes.toArray).asRight[(Option[DeployData], Failed)].pure[F] } } doReplayEval(Blake2b256Hash.fromByteArray(start.toByteArray), processedDeploys) }

Status

Assignee

Artur Gajowy

Reporter

Joseph Denman

Components

Story Points

10

Labels

None

Sprint

Priority

High