diff --git a/tests/mbt/driver/model_viewer.go b/tests/mbt/driver/model_viewer.go index 180b79f179..4d594fb472 100644 --- a/tests/mbt/driver/model_viewer.go +++ b/tests/mbt/driver/model_viewer.go @@ -91,3 +91,11 @@ func VscSendTimestamps(curStateExpr itf.MapExprType, consumer string) []int64 { } return res } + +func PacketsToAckOnEndBlock(curStateExpr itf.MapExprType) itf.MapExprType { + return ProviderState(curStateExpr)["acksToSendOnEndBlock"].Value.(itf.MapExprType) +} + +func WaitingForAcks(curStateExpr itf.MapExprType, consumer string) itf.ListExprType { + return ConsumerState(curStateExpr, consumer)["waitingForSlashPacketAck"].Value.(itf.ListExprType) +} diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index db53368957..c8b9764cdc 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -419,6 +419,8 @@ func (s *Driver) setupProvider( // set the CcvTimeoutPeriod providerParams := s.providerKeeper().GetParams(s.ctx("provider")) providerParams.CcvTimeoutPeriod = params.CcvTimeout[ChainId(providerChain.ChainID)] + providerParams.SlashMeterReplenishFraction = "1" + providerParams.SlashMeterReplenishPeriod = time.Nanosecond s.providerKeeper().SetParams(s.ctx("provider"), providerParams) // set the signing infos diff --git a/tests/mbt/model/ccv.qnt b/tests/mbt/model/ccv.qnt index b95d16d01d..d6fa90e014 100644 --- a/tests/mbt/model/ccv.qnt +++ b/tests/mbt/model/ccv.qnt @@ -436,7 +436,10 @@ module ccv { currentState.providerState.acksToSendOnEndBlock.getOrElse(sender, List()).prepend(packet) ) ) - val result = recvPacketOnProvider(currentState, sender, packet) + val newState: ProtocolState = currentState.with( + "providerState", newProviderState + ) + val result = recvPacketOnProvider(newState, sender, packet) val tmpState = result.newState if (result.hasError()) { (result, false) @@ -630,7 +633,7 @@ module ccv { ) newConsumerState } else { - currentState.consumerStates.get(consumer) + tmpState2.consumerStates.get(consumer) } ) val newState = tmpState2.with( @@ -689,16 +692,16 @@ module ccv { match packet { | VscMatured(p) => VscMatured({ id: p.id, - sendingTime: newChainState.runningTimestamp, - timeoutTime: newChainState.runningTimestamp + CcvTimeout.get(chain) + sendingTime: oldChainState.runningTimestamp, + timeoutTime: oldChainState.runningTimestamp + CcvTimeout.get(chain) }) | Slash(p) => Slash({ validator: p.validator, id: p.id, downtime: p.downtime, valPower: p.valPower, - sendingTime: newChainState.runningTimestamp, - timeoutTime: newChainState.runningTimestamp + CcvTimeout.get(chain) + sendingTime: oldChainState.runningTimestamp, + timeoutTime: oldChainState.runningTimestamp + CcvTimeout.get(chain) }) | _ => packet } @@ -708,10 +711,10 @@ module ccv { val tmp = if (haveOutstandingSlash) { // if we have an outstanding slash, send nothing and keep everything queued - (List(), newQueuedPackets) + (List(), newQueuedPackets2) } else { // otherwise, add all packets from the queue before the first slash packet - newQueuedPackets.splitAfterFirst( + newQueuedPackets2.splitAfterFirst( packet => packet.IsSlashPacket() ) } @@ -910,6 +913,9 @@ module ccv { currentState.providerState } + // if the validator did not have voting power of 0, the validator set will change due to the slash + val valSetChanged = packet.downtime and currentState.providerState.chainState.currentValidatorPowers.get(providerVal) != 0 + if (packet.downtime) { // if the packet is for downtime, add the consumer address to the list of acknowledged slashes // for the sender chain of this slash packet and indicate that we need to send a packet at endblock @@ -919,7 +925,7 @@ module ccv { val newProviderState2 = newProviderState.with( "downtimeSlashRequests", newProviderState.downtimeSlashRequests.put(sender, newDowntimeSlashRequests) ).with( - "providerValidatorSetChangedInThisBlock", true + "providerValidatorSetChangedInThisBlock", newProviderState.providerValidatorSetChangedInThisBlock or valSetChanged ) Ok(currentState.with("providerState", newProviderState2)) } else { diff --git a/tests/mbt/model/ccv_model.qnt b/tests/mbt/model/ccv_model.qnt index 3b581d0488..d13a3e327a 100644 --- a/tests/mbt/model/ccv_model.qnt +++ b/tests/mbt/model/ccv_model.qnt @@ -1150,5 +1150,56 @@ module ccv_model { VotingPowerChange("node1", 50) } ) + + run SlashAckTest = + init + .then( + // start consumer 1 + EndAndBeginBlockForProvider(1 * Second, Set("consumer1"), Set()) + ) + .then( + // change voting power for node 1 by 50 + VotingPowerChange("node1", 50) + ) + .then( + // end and begin a block on the provider + EndAndBeginBlockForProvider(1 * Second, Set(), Set()) + ) + .then( + // deliver the vsc packet to consumer 1 + DeliverVscPacket("consumer1") + ) + .then( + // initiate a slash for downtime + ConsumerInitiatedSlashDet("consumer1", "node1", 1, true) + ) + .then( + // end and begin a block for consumer 1 to send the packet + EndAndBeginBlockForConsumer("consumer1", 1 * Second) + ) + .then( + all { + assert(currentState.consumerStates.get("consumer1").outstandingPacketsToProvider.length() == 1), + assert(currentState.consumerStates.get("consumer1").waitingForSlashPacketAck.size() == 1), + // deliver the slash request to the provider + DeliverPacketToProvider("consumer1") + } + ) + // .then( + // // ensure that the provider will send a slash ack to consumer 1 on endblock + // all { + // assert(currentState.providerState.acksToSendOnEndBlock.get("consumer1").length() == 1), + // // end a block on the provider, which should send the ack + // EndAndBeginBlockForProvider(1 * Second, Set(), Set()) + // } + // ) + // .then( + // all { + // // the ack should have been received by the consumer + // assert(currentState.consumerStates.get("consumer1").waitingForSlashPacketAck.size() == 0), + // // action does not matter + // VotingPowerChange("node1", 50) + // } + // ) } \ No newline at end of file