GameStates refactoring
This commit is contained in:
parent
959ea0051d
commit
9004e8a408
@ -21,15 +21,15 @@ public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
|
||||
switch (command.action) {
|
||||
case GAME_PROPOSAL_ACCEPT:
|
||||
GameCommand.validateGameProposalAccept(trx);
|
||||
command.validateGameProposalAccept(trx);
|
||||
break;
|
||||
|
||||
case GAME_BOARD_MOVE:
|
||||
GameCommand.validateGameBoardMove(trx);
|
||||
command.validateGameBoardMove(trx);
|
||||
break;
|
||||
|
||||
case GAME_BOARD_SURRENDER:
|
||||
GameCommand.validateGameBoardSurrender(trx);
|
||||
command.validateGameBoardSurrender(trx);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1,5 +1,11 @@
|
||||
package djmil.cordacheckers.contracts;
|
||||
|
||||
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleInputState;
|
||||
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleOutputState;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import djmil.cordacheckers.states.GameBoardState;
|
||||
import djmil.cordacheckers.states.GameProposalState;
|
||||
import djmil.cordacheckers.states.GameResultState;
|
||||
@ -11,13 +17,6 @@ import net.corda.v5.ledger.utxo.Command;
|
||||
import net.corda.v5.ledger.utxo.StateAndRef;
|
||||
import net.corda.v5.ledger.utxo.transaction.UtxoLedgerTransaction;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleInputState;
|
||||
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleOutputState;
|
||||
|
||||
public class GameCommand implements Command {
|
||||
@CordaSerializable
|
||||
public static enum Action {
|
||||
@ -78,48 +77,49 @@ public class GameCommand implements Command {
|
||||
/*
|
||||
* Session initiator/respondent
|
||||
*/
|
||||
|
||||
public MemberX500Name getObserver(StateAndRef<GameState> gameStateSar) {
|
||||
public MemberX500Name getCounterparty(StateAndRef<GameState> gameStateSar) {
|
||||
final GameState gameState = gameStateSar.getState().getContractState();
|
||||
return gameState.getCounterpartyName(getActor(gameState));
|
||||
return gameState.getOpponentName(getInitiator(gameState));
|
||||
}
|
||||
|
||||
public MemberX500Name getActor(StateAndRef<GameState> gameStateSar) {
|
||||
return getActor(gameStateSar.getState().getContractState());
|
||||
public MemberX500Name getCounterparty(GameState gameState) {
|
||||
return gameState.getOpponentName(getInitiator(gameState));
|
||||
}
|
||||
|
||||
public MemberX500Name getObserver(GameState gameState) {
|
||||
return gameState.getCounterpartyName(getActor(gameState));
|
||||
public MemberX500Name getInitiator(StateAndRef<GameState> gameStateSar) {
|
||||
return getInitiator(gameStateSar.getState().getContractState());
|
||||
}
|
||||
|
||||
public MemberX500Name getActor(GameState gameState) {
|
||||
public MemberX500Name getInitiator(GameState gameState) {
|
||||
switch (action) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
case GAME_PROPOSAL_CANCEL:
|
||||
if (gameState instanceof GameProposalState)
|
||||
return ((GameProposalState)gameState).getIssuer();
|
||||
if (gameState instanceof GameProposalState)
|
||||
return ((GameProposalState)gameState).getIssuerName();
|
||||
break;
|
||||
|
||||
case GAME_PROPOSAL_REJECT:
|
||||
if (gameState instanceof GameProposalState)
|
||||
return ((GameProposalState)gameState).getAcquier();
|
||||
return ((GameProposalState)gameState).getAcquierName();
|
||||
break;
|
||||
|
||||
case GAME_PROPOSAL_ACCEPT:
|
||||
if (gameState instanceof GameProposalState) // <<-- Session validation perspective
|
||||
return ((GameProposalState)gameState).getAcquier();
|
||||
return ((GameProposalState)gameState).getAcquierName();
|
||||
if (gameState instanceof GameBoardState) // <<-- GameViewBuilder perspective
|
||||
return ((GameBoardState)gameState).getMovePlayerName();
|
||||
return ((GameBoardState)gameState).getActivePlayerName();
|
||||
break;
|
||||
|
||||
case GAME_BOARD_SURRENDER:
|
||||
if (gameState instanceof GameBoardState) // <<-- Session validation perspective
|
||||
return ((GameBoardState)gameState).getActivePlayerName();
|
||||
if (gameState instanceof GameResultState) // <<-- GameViewBuilder perspective
|
||||
return ((GameResultState)gameState).getLooserName();
|
||||
break;
|
||||
|
||||
case GAME_BOARD_MOVE:
|
||||
if (gameState instanceof GameBoardState)
|
||||
return ((GameBoardState)gameState).getMovePlayerName();
|
||||
break;
|
||||
|
||||
case GAME_BOARD_SURRENDER:
|
||||
if (gameState instanceof GameResultState)
|
||||
return ((GameResultState)gameState).getOpponentName();
|
||||
return ((GameBoardState)gameState).getActivePlayerName();
|
||||
break;
|
||||
|
||||
case GAME_RESULT_CREATE:
|
||||
@ -138,75 +138,79 @@ public class GameCommand implements Command {
|
||||
* Transaction validation
|
||||
*/
|
||||
|
||||
public static void validateGameProposalCreate(UtxoLedgerTransaction trx) {
|
||||
public void validateGameProposalCreate(UtxoLedgerTransaction trx) {
|
||||
requireThat(trx.getInputContractStates().isEmpty(), CREATE_INPUT_STATE);
|
||||
requireThat(trx.getOutputContractStates().size() == 1, CREATE_OUTPUT_STATE);
|
||||
|
||||
GameProposalState outputState = getSingleOutputState(trx, GameProposalState.class);
|
||||
final GameProposalState gameProposal = getSingleOutputState(trx, GameProposalState.class);
|
||||
|
||||
requireThat(outputState.getAcquierColor() != null, NON_NULL_RECIPIENT_COLOR);
|
||||
requireThat(gameProposal.getOpponentName(gameProposal.getIssuerName()).compareTo(gameProposal.getAcquierName()) == 0,
|
||||
"GameProposal.Issuer must be either Black or White player");
|
||||
}
|
||||
|
||||
public static void validateGameProposalAccept(UtxoLedgerTransaction trx) {
|
||||
public void validateGameProposalAccept(UtxoLedgerTransaction trx) {
|
||||
requireThat(trx.getInputContractStates().size() == 1, ACCEPT_INPUT_STATE);
|
||||
requireThat(trx.getOutputContractStates().size() == 1, ACCEPT_OUTPUT_STATE);
|
||||
|
||||
GameProposalState inGameProposal = getSingleInputState(trx, GameProposalState.class);
|
||||
GameBoardState outGameBoard = getSingleOutputState(trx, GameBoardState.class);
|
||||
final GameProposalState inGameProposal = getSingleInputState(trx, GameProposalState.class);
|
||||
final GameBoardState outGameBoard = getSingleOutputState(trx, GameBoardState.class);
|
||||
|
||||
requireThat(outGameBoard.getParticipants().containsAll(inGameProposal.getParticipants()), IN_OUT_PARTICIPANTS);
|
||||
requireThat(inGameProposal.getParticipants().containsAll(outGameBoard.getParticipants()), IN_OUT_PARTICIPANTS);
|
||||
}
|
||||
|
||||
public static void validateGameProposalReject(UtxoLedgerTransaction trx) {
|
||||
public void validateGameProposalReject(UtxoLedgerTransaction trx) {
|
||||
requireThat(trx.getInputContractStates().size() == 1, REJECT_INPUT_STATE);
|
||||
requireThat(trx.getOutputContractStates().isEmpty(), REJECT_OUTPUT_STATE);
|
||||
|
||||
getSingleInputState(trx, GameProposalState.class);
|
||||
}
|
||||
|
||||
public static void validateGameProposalCancel(UtxoLedgerTransaction trx) {
|
||||
public void validateGameProposalCancel(UtxoLedgerTransaction trx) {
|
||||
requireThat(trx.getInputContractStates().size() == 1, CANCEL_INPUT_STATE);
|
||||
requireThat(trx.getOutputContractStates().isEmpty(), CANCEL_OUTPUT_STATE);
|
||||
|
||||
getSingleInputState(trx, GameProposalState.class);
|
||||
}
|
||||
|
||||
public static void validateGameBoardSurrender(UtxoLedgerTransaction trx) {
|
||||
public void validateGameBoardSurrender(UtxoLedgerTransaction trx) {
|
||||
requireThat(trx.getInputContractStates().size() == 1, SURRENDER_INPUT_STATE);
|
||||
final var inGameBoardState = getSingleInputState(trx, GameBoardState.class);
|
||||
|
||||
requireThat(trx.getOutputContractStates().size() == 1, SURRENDER_OUTPUT_STATE);
|
||||
final var outGameResultState = getSingleOutputState(trx, GameResultState.class);
|
||||
|
||||
|
||||
List<MemberX500Name> inActors = new LinkedList<MemberX500Name>(List.of(
|
||||
inGameBoardState.getWhitePlayerName(),
|
||||
inGameBoardState.getBlackPlayerName())
|
||||
inGameBoardState.getWhitePlayer(),
|
||||
inGameBoardState.getBlackPlayer())
|
||||
);
|
||||
|
||||
List<MemberX500Name> outActors = new LinkedList<MemberX500Name>(List.of(
|
||||
outGameResultState.getWinnerName(),
|
||||
outGameResultState.getOpponentName())
|
||||
outGameResultState.getWhitePlayer(),
|
||||
outGameResultState.getBlackPlayer())
|
||||
);
|
||||
|
||||
requireThat(inActors.containsAll(outActors) && outActors.containsAll(inActors), IN_OUT_PARTICIPANTS);
|
||||
|
||||
final var activePlayerName = outGameResultState.getCounterpartyName(outGameResultState.getWinnerName());
|
||||
requireThat(inGameBoardState.getMovePlayerName().compareTo(activePlayerName) == 0, SURRENDER_ACTOR + "expected " +inGameBoardState.getMovePlayerName() +" actual " +activePlayerName);
|
||||
final var activePlayerName = getInitiator(inGameBoardState);
|
||||
requireThat(inGameBoardState.getActivePlayerName().compareTo(activePlayerName) == 0, SURRENDER_ACTOR + "expected " +inGameBoardState.getActivePlayerName() +" actual " +activePlayerName);
|
||||
|
||||
final var expectedWinnerName = inGameBoardState.getOpponentName(activePlayerName);
|
||||
requireThat(outGameResultState.getWinnerName().compareTo(expectedWinnerName) == 0,
|
||||
"Expected winner "+expectedWinnerName.getCommonName() +", proposed winner " +outGameResultState.getWinnerName().getCommonName());
|
||||
}
|
||||
|
||||
public static void validateGameBoardMove(UtxoLedgerTransaction trx) {
|
||||
public void validateGameBoardMove(UtxoLedgerTransaction trx) {
|
||||
requireThat(trx.getInputContractStates().size() == 1, MOVE_INPUT_STATE);
|
||||
final var inGameBoardState = getSingleInputState(trx, GameBoardState.class);
|
||||
|
||||
requireThat(trx.getOutputContractStates().size() == 1, MOVE_OUTPUT_STATE);
|
||||
final var outGameBoardState = getSingleOutputState(trx, GameBoardState.class);
|
||||
|
||||
requireThat(inGameBoardState.getWhitePlayerName().compareTo(outGameBoardState.getWhitePlayerName()) == 0, IN_OUT_PARTICIPANTS);
|
||||
requireThat(inGameBoardState.getBlackPlayerName().compareTo(outGameBoardState.getBlackPlayerName()) == 0, IN_OUT_PARTICIPANTS);
|
||||
requireThat(inGameBoardState.getWhitePlayer().compareTo(outGameBoardState.getWhitePlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||
requireThat(inGameBoardState.getBlackPlayer().compareTo(outGameBoardState.getBlackPlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||
}
|
||||
|
||||
public static void validateGameResultCreate(UtxoLedgerTransaction trx) {
|
||||
public void validateGameResultCreate(UtxoLedgerTransaction trx) {
|
||||
throw new RuntimeException("Unimplemented");
|
||||
}
|
||||
|
||||
@ -221,7 +225,6 @@ public class GameCommand implements Command {
|
||||
|
||||
static final String CREATE_INPUT_STATE = "Create command should have no input states";
|
||||
static final String CREATE_OUTPUT_STATE = "Create command should output exactly one GameProposal state";
|
||||
static final String NON_NULL_RECIPIENT_COLOR = "GameProposal.recipientColor field can not be null";
|
||||
|
||||
static final String REJECT_INPUT_STATE = "Reject command should have exactly one GameProposal input state";
|
||||
static final String REJECT_OUTPUT_STATE = "Reject command should have no output states";
|
||||
|
@ -21,19 +21,19 @@ public class GameProposalContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
|
||||
switch (command.action) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
GameCommand.validateGameProposalCreate(trx);
|
||||
command.validateGameProposalCreate(trx);
|
||||
break;
|
||||
|
||||
case GAME_PROPOSAL_ACCEPT:
|
||||
GameCommand.validateGameProposalAccept(trx);
|
||||
command.validateGameProposalAccept(trx);
|
||||
break;
|
||||
|
||||
case GAME_PROPOSAL_REJECT:
|
||||
GameCommand.validateGameProposalReject(trx);
|
||||
command.validateGameProposalReject(trx);
|
||||
break;
|
||||
|
||||
case GAME_PROPOSAL_CANCEL:
|
||||
GameCommand.validateGameProposalCancel(trx);
|
||||
command.validateGameProposalCancel(trx);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -21,11 +21,11 @@ public class GameResultContract implements net.corda.v5.ledger.utxo.Contract {
|
||||
|
||||
switch (command.action) {
|
||||
case GAME_BOARD_SURRENDER:
|
||||
GameCommand.validateGameBoardSurrender(trx);
|
||||
command.validateGameBoardSurrender(trx);
|
||||
break;
|
||||
|
||||
case GAME_RESULT_CREATE:
|
||||
GameCommand.validateGameResultCreate(trx);
|
||||
command.validateGameResultCreate(trx);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -14,19 +14,13 @@ import net.corda.v5.ledger.utxo.BelongsToContract;
|
||||
|
||||
@BelongsToContract(GameBoardContract.class)
|
||||
public class GameBoardState extends GameState {
|
||||
|
||||
private final MemberX500Name whitePlayerName;
|
||||
private final MemberX500Name blackPlayerName;
|
||||
|
||||
private final Piece.Color moveColor;
|
||||
private final Integer moveNumber;
|
||||
private final Map<Integer, Piece> board;
|
||||
|
||||
public GameBoardState(GameProposalState gameProposalState) {
|
||||
super(gameProposalState.gameUuid, gameProposalState.message, gameProposalState.participants);
|
||||
|
||||
this.whitePlayerName = gameProposalState.getWhitePlayerName();
|
||||
this.blackPlayerName = gameProposalState.getBlackPlayerName();
|
||||
super(gameProposalState.whitePlayer, gameProposalState.blackPlayer,
|
||||
gameProposalState.gameUuid, gameProposalState.message, gameProposalState.participants);
|
||||
|
||||
// Initial GameBoard state
|
||||
this.moveColor = Piece.Color.WHITE;
|
||||
@ -34,43 +28,26 @@ public class GameBoardState extends GameState {
|
||||
this.board = new LinkedHashMap<Integer, Piece>(initialBoard);
|
||||
}
|
||||
|
||||
public GameBoardState(
|
||||
GameBoardState oldGameBoardState, Map<Integer, Piece> newBoard, Piece.Color moveColor) {
|
||||
super(oldGameBoardState.gameUuid, oldGameBoardState.message, oldGameBoardState.participants);
|
||||
|
||||
this.whitePlayerName = oldGameBoardState.getWhitePlayerName();
|
||||
this.blackPlayerName = oldGameBoardState.getBlackPlayerName();
|
||||
public GameBoardState(GameBoardState oldGameBoardState, Map<Integer, Piece> newBoard, Piece.Color moveColor) {
|
||||
super(oldGameBoardState.whitePlayer, oldGameBoardState.blackPlayer,
|
||||
oldGameBoardState.gameUuid, oldGameBoardState.message, oldGameBoardState.participants);
|
||||
|
||||
// Initial GameBoard state
|
||||
this.moveColor = moveColor;
|
||||
this.moveNumber = oldGameBoardState.getMoveNumber() +1;
|
||||
this.board = newBoard;
|
||||
}
|
||||
|
||||
@ConstructorForDeserialization
|
||||
public GameBoardState(MemberX500Name whitePlayerName, MemberX500Name blackPlayerName,
|
||||
public GameBoardState(MemberX500Name whitePlayer, MemberX500Name blackPlayer,
|
||||
Color moveColor, Integer moveNumber, Map<Integer, Piece> board, String message,
|
||||
UUID gameUuid, List<PublicKey> participants) {
|
||||
super(gameUuid, message, participants);
|
||||
super(whitePlayer, blackPlayer, gameUuid, message, participants);
|
||||
|
||||
this.whitePlayerName = whitePlayerName;
|
||||
this.blackPlayerName = blackPlayerName;
|
||||
this.moveColor = moveColor;
|
||||
this.moveNumber = moveNumber;
|
||||
this.board = board;
|
||||
}
|
||||
|
||||
public MemberX500Name getMovePlayerName() {
|
||||
switch (moveColor) {
|
||||
case WHITE:
|
||||
return whitePlayerName;
|
||||
case BLACK:
|
||||
return blackPlayerName;
|
||||
default:
|
||||
throw new Piece.Color.UnknownException();
|
||||
}
|
||||
}
|
||||
|
||||
public Piece.Color getMoveColor() {
|
||||
return moveColor;
|
||||
}
|
||||
@ -79,26 +56,14 @@ public class GameBoardState extends GameState {
|
||||
return moveNumber;
|
||||
}
|
||||
|
||||
public MemberX500Name getActivePlayerName() {
|
||||
return moveColor == Piece.Color.WHITE ? whitePlayer : blackPlayer;
|
||||
}
|
||||
|
||||
public Map<Integer, Piece> getBoard() {
|
||||
return board;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberX500Name getWhitePlayerName() {
|
||||
return whitePlayerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberX500Name getCounterpartyName(MemberX500Name myName) throws NotInvolved {
|
||||
if (whitePlayerName.compareTo(myName) == 0)
|
||||
return blackPlayerName;
|
||||
|
||||
if (blackPlayerName.compareTo(myName) == 0)
|
||||
return whitePlayerName;
|
||||
|
||||
throw new GameState.NotInvolved(myName, GameBoardState.class, this.gameUuid);
|
||||
}
|
||||
|
||||
// TODO: move to contract
|
||||
public final static Map<Integer, Piece> initialBoard = Map.ofEntries(
|
||||
// Inspired by Checkers notation rules: https://www.bobnewell.net/nucleus/checkers.php
|
||||
|
@ -12,50 +12,21 @@ import net.corda.v5.ledger.utxo.BelongsToContract;
|
||||
@BelongsToContract(GameProposalContract.class)
|
||||
public class GameProposalState extends GameState {
|
||||
|
||||
private final MemberX500Name issuer;
|
||||
private final MemberX500Name acquier;
|
||||
private final Piece.Color acquierColor;
|
||||
private final MemberX500Name issuerName;
|
||||
|
||||
@ConstructorForDeserialization
|
||||
public GameProposalState(
|
||||
MemberX500Name issuer,
|
||||
MemberX500Name acquier,
|
||||
Piece.Color acquierColor,
|
||||
String message,
|
||||
UUID gameUuid,
|
||||
List<PublicKey> participants
|
||||
) {
|
||||
super(gameUuid, message, participants);
|
||||
this.issuer = issuer;
|
||||
this.acquier = acquier;
|
||||
this.acquierColor = acquierColor;
|
||||
public GameProposalState(MemberX500Name whitePlayer, MemberX500Name blackPlayer, MemberX500Name issuerName,
|
||||
UUID gameUuid, String message, List<PublicKey> participants) {
|
||||
super(whitePlayer, blackPlayer, gameUuid, message, participants);
|
||||
this.issuerName = issuerName;
|
||||
}
|
||||
|
||||
public MemberX500Name getIssuer() {
|
||||
return issuer;
|
||||
public MemberX500Name getIssuerName() {
|
||||
return issuerName;
|
||||
}
|
||||
|
||||
public MemberX500Name getAcquier() {
|
||||
return acquier;
|
||||
}
|
||||
|
||||
public Piece.Color getAcquierColor() {
|
||||
return acquierColor;
|
||||
}
|
||||
|
||||
public MemberX500Name getWhitePlayerName() {
|
||||
return acquierColor == Piece.Color.WHITE ? getAcquier() : getIssuer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberX500Name getCounterpartyName(MemberX500Name myName) throws NotInvolved {
|
||||
if (issuer.compareTo(myName) == 0)
|
||||
return acquier;
|
||||
|
||||
if (acquier.compareTo(myName) == 0)
|
||||
return issuer;
|
||||
|
||||
throw new GameState.NotInvolved(myName, GameProposalState.class, this.gameUuid);
|
||||
public MemberX500Name getAcquierName() {
|
||||
return getOpponentName(issuerName);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,52 +13,25 @@ import net.corda.v5.ledger.utxo.BelongsToContract;
|
||||
public class GameResultState extends GameState {
|
||||
|
||||
private final MemberX500Name winnerName;
|
||||
private final MemberX500Name opponentName;
|
||||
|
||||
private final Piece.Color winnerColor;
|
||||
|
||||
@ConstructorForDeserialization
|
||||
public GameResultState(MemberX500Name winnerName, MemberX500Name opponentName, Piece.Color winnerColor,
|
||||
public GameResultState(MemberX500Name whitePlayer, MemberX500Name blackPlayer, MemberX500Name winnerName,
|
||||
UUID gameUuid, String message, List<PublicKey> participants) {
|
||||
super(gameUuid, message, participants);
|
||||
super(whitePlayer, blackPlayer, gameUuid, message, participants);
|
||||
this.winnerName = winnerName;
|
||||
this.opponentName = opponentName;
|
||||
this.winnerColor = winnerColor;
|
||||
}
|
||||
|
||||
public GameResultState(GameBoardState gameBoardState, MemberX500Name winnerName) {
|
||||
super(gameBoardState.gameUuid, null, gameBoardState.participants);
|
||||
this.opponentName = gameBoardState.getCounterpartyName(winnerName);
|
||||
super(gameBoardState.whitePlayer, gameBoardState.blackPlayer, gameBoardState.gameUuid, null, gameBoardState.participants);
|
||||
this.winnerName = winnerName;
|
||||
this.winnerColor = gameBoardState.getWhitePlayerName().compareTo(winnerName) == 0 ? Piece.Color.WHITE : Piece.Color.BLACK;
|
||||
}
|
||||
|
||||
public MemberX500Name getWinnerName() {
|
||||
return winnerName;
|
||||
}
|
||||
|
||||
public MemberX500Name getOpponentName() {
|
||||
return opponentName;
|
||||
}
|
||||
|
||||
public Piece.Color getWinnerColor() {
|
||||
return winnerColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberX500Name getCounterpartyName(MemberX500Name myName) throws NotInvolved {
|
||||
if (winnerName.compareTo(myName) == 0)
|
||||
return opponentName;
|
||||
|
||||
if (opponentName.compareTo(myName) == 0)
|
||||
return winnerName;
|
||||
|
||||
throw new GameState.NotInvolved(myName, GameResultState.class, this.gameUuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberX500Name getWhitePlayerName() {
|
||||
return winnerColor == Piece.Color.WHITE ? winnerName : opponentName;
|
||||
public MemberX500Name getLooserName() {
|
||||
return getOpponentName(getWinnerName());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,30 +4,35 @@ import java.security.PublicKey;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.corda.v5.base.annotations.CordaSerializable;
|
||||
import net.corda.v5.base.types.MemberX500Name;
|
||||
import net.corda.v5.ledger.utxo.ContractState;
|
||||
|
||||
@CordaSerializable
|
||||
public abstract class GameState implements ContractState {
|
||||
final MemberX500Name whitePlayer;
|
||||
final MemberX500Name blackPlayer;
|
||||
final UUID gameUuid;
|
||||
final String message;
|
||||
final List<PublicKey> participants;
|
||||
|
||||
@NotNull
|
||||
public abstract MemberX500Name getWhitePlayerName();
|
||||
|
||||
@NotNull
|
||||
public abstract MemberX500Name getCounterpartyName(MemberX500Name myName) throws NotInvolved;
|
||||
|
||||
GameState(UUID gameUuid, String message, List<PublicKey> participants) {
|
||||
GameState(MemberX500Name whitePlayer, MemberX500Name blackPlayer, UUID gameUuid,
|
||||
String message, List<PublicKey> participants) {
|
||||
this.whitePlayer = whitePlayer;
|
||||
this.blackPlayer = blackPlayer;
|
||||
this.gameUuid = gameUuid;
|
||||
this.message = message;
|
||||
this.participants = participants;
|
||||
}
|
||||
|
||||
public MemberX500Name getWhitePlayer() {
|
||||
return whitePlayer;
|
||||
}
|
||||
|
||||
public MemberX500Name getBlackPlayer() {
|
||||
return blackPlayer;
|
||||
}
|
||||
|
||||
public UUID getGameUuid() {
|
||||
return gameUuid;
|
||||
}
|
||||
@ -36,18 +41,25 @@ public abstract class GameState implements ContractState {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PublicKey> getParticipants() {
|
||||
return participants;
|
||||
}
|
||||
|
||||
public MemberX500Name getBlackPlayerName() {
|
||||
return getCounterpartyName(getWhitePlayerName());
|
||||
public MemberX500Name getOpponentName(MemberX500Name playerName) throws NotInvolved {
|
||||
if (playerName.compareTo(whitePlayer) == 0)
|
||||
return blackPlayer;
|
||||
if (playerName.compareTo(blackPlayer) == 0)
|
||||
return whitePlayer;
|
||||
throw new NotInvolved(playerName, this.getClass(), gameUuid);
|
||||
}
|
||||
|
||||
public Piece.Color getCounterpartyColor(MemberX500Name myName) throws NotInvolved {
|
||||
final MemberX500Name opponentName = getCounterpartyName(myName);
|
||||
|
||||
return getWhitePlayerName().compareTo(opponentName) == 0 ? Piece.Color.WHITE : Piece.Color.BLACK;
|
||||
public Piece.Color getOpponentColor(MemberX500Name playerName) throws NotInvolved {
|
||||
if (playerName.compareTo(whitePlayer) == 0)
|
||||
return Piece.Color.BLACK;
|
||||
if (playerName.compareTo(blackPlayer) == 0)
|
||||
return Piece.Color.WHITE;
|
||||
throw new NotInvolved(playerName, this.getClass(), gameUuid);
|
||||
}
|
||||
|
||||
public static class NotInvolved extends RuntimeException {
|
||||
|
@ -52,7 +52,7 @@ public class SurrenderFlow implements ClientStartableFlow{
|
||||
@Suspendable
|
||||
@Override
|
||||
public String call(ClientRequestBody requestBody) {
|
||||
SecureHash gameStateUtxoTrxId = null;
|
||||
SecureHash utxoTrxId = null;
|
||||
|
||||
try {
|
||||
final GameCommand command = new GameCommand(GameCommand.Action.GAME_BOARD_SURRENDER);
|
||||
@ -64,7 +64,7 @@ public class SurrenderFlow implements ClientStartableFlow{
|
||||
|
||||
final GameResultState outputState = prepareGameResultState(inputStateSar);
|
||||
|
||||
final UtxoSignedTransaction transactionCandidate = utxoLedgerService.createTransactionBuilder()
|
||||
final UtxoSignedTransaction gameBoardSurrenderTrx = utxoLedgerService.createTransactionBuilder()
|
||||
.addCommand(command)
|
||||
.addInputState(inputStateSar.getRef())
|
||||
.addOutputState(outputState)
|
||||
@ -73,19 +73,19 @@ public class SurrenderFlow implements ClientStartableFlow{
|
||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||
.toSignedTransaction();
|
||||
|
||||
gameStateUtxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(transactionCandidate, command.getObserver(outputState)));
|
||||
utxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameBoardSurrenderTrx, command.getCounterparty(inputStateSar)));
|
||||
|
||||
final View gameStateView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(gameStateUtxoTrxId));
|
||||
.subFlow(new ViewBuilder(utxoTrxId));
|
||||
|
||||
return new FlowResponce(gameStateView, gameStateUtxoTrxId)
|
||||
return new FlowResponce(gameStateView, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
||||
e.printStackTrace(System.out);
|
||||
return new FlowResponce(e, gameStateUtxoTrxId)
|
||||
return new FlowResponce(e, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@ public class SurrenderFlow implements ClientStartableFlow{
|
||||
final GameBoardState gameBoard = (GameBoardState) gameState;
|
||||
|
||||
final MemberX500Name myName = memberLookup.myInfo().getName();
|
||||
final MemberX500Name winnerName = gameBoard.getCounterpartyName(myName);
|
||||
final MemberX500Name winnerName = gameBoard.getOpponentName(myName);
|
||||
|
||||
return new GameResultState(gameBoard, winnerName);
|
||||
}
|
||||
|
@ -43,40 +43,41 @@ public class AcceptFlow implements ClientStartableFlow{
|
||||
@Suspendable
|
||||
@Override
|
||||
public String call(ClientRequestBody requestBody) {
|
||||
SecureHash gameStateUtxoTrxId = null;
|
||||
SecureHash utxoTrxId = null;
|
||||
|
||||
try {
|
||||
final GameCommand command = new GameCommand(GameCommand.Action.GAME_PROPOSAL_ACCEPT);
|
||||
|
||||
final UUID gameStateUuid = UUID.fromString(requestBody.getRequestBody());
|
||||
final UUID gameUuid = UUID.fromString(requestBody.getRequestBody());
|
||||
|
||||
final StateAndRef<GameState> inputState = this.flowEngine
|
||||
.subFlow(new GetFlow(gameStateUuid));
|
||||
final StateAndRef<GameState> gameProposalSar = this.flowEngine
|
||||
.subFlow(new GetFlow(gameUuid));
|
||||
final GameProposalState gameProposal = (GameProposalState)gameProposalSar.getState().getContractState();
|
||||
|
||||
final GameBoardState outputState = new GameBoardState((GameProposalState)inputState.getState().getContractState());
|
||||
final GameBoardState gameBoard = new GameBoardState(gameProposal); // <<-- accepted
|
||||
|
||||
final UtxoSignedTransaction gameStateRejectTrx = utxoLedgerService.createTransactionBuilder()
|
||||
final UtxoSignedTransaction gameProposalAcceptTrx = utxoLedgerService.createTransactionBuilder()
|
||||
.addCommand(command)
|
||||
.addInputState(inputState.getRef())
|
||||
.addOutputState(outputState)
|
||||
.addSignatories(inputState.getState().getContractState().getParticipants())
|
||||
.setNotary(inputState.getState().getNotaryName())
|
||||
.addInputState(gameProposalSar.getRef())
|
||||
.addOutputState(gameBoard)
|
||||
.addSignatories(gameProposal.getParticipants())
|
||||
.setNotary(gameProposalSar.getState().getNotaryName())
|
||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||
.toSignedTransaction();
|
||||
|
||||
gameStateUtxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameStateRejectTrx, command.getObserver(inputState)));
|
||||
utxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameProposalAcceptTrx, command.getCounterparty(gameProposal)));
|
||||
|
||||
final View gameStateView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(gameStateUtxoTrxId));
|
||||
final View gameView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(utxoTrxId));
|
||||
|
||||
return new FlowResponce(gameStateView, gameStateUtxoTrxId)
|
||||
return new FlowResponce(gameView, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
||||
e.printStackTrace(System.out);
|
||||
return new FlowResponce(e, gameStateUtxoTrxId)
|
||||
return new FlowResponce(e, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import djmil.cordacheckers.gamestate.FlowResponce;
|
||||
import djmil.cordacheckers.gamestate.GetFlow;
|
||||
import djmil.cordacheckers.gamestate.View;
|
||||
import djmil.cordacheckers.gamestate.ViewBuilder;
|
||||
import djmil.cordacheckers.states.GameProposalState;
|
||||
import djmil.cordacheckers.states.GameState;
|
||||
import net.corda.v5.application.flows.ClientRequestBody;
|
||||
import net.corda.v5.application.flows.ClientStartableFlow;
|
||||
@ -41,36 +42,37 @@ public class CancelFlow implements ClientStartableFlow{
|
||||
@Suspendable
|
||||
@Override
|
||||
public String call(ClientRequestBody requestBody) {
|
||||
SecureHash gameStateUtxoTrxId = null;
|
||||
SecureHash utxoTrxId = null;
|
||||
|
||||
try {
|
||||
final GameCommand command = new GameCommand(GameCommand.Action.GAME_PROPOSAL_CANCEL);
|
||||
|
||||
final UUID gameStateUuid = UUID.fromString(requestBody.getRequestBody());
|
||||
final UUID gameUuid = UUID.fromString(requestBody.getRequestBody());
|
||||
|
||||
final StateAndRef<GameState> inputState = this.flowEngine
|
||||
.subFlow(new GetFlow(gameStateUuid));
|
||||
final StateAndRef<GameState> gameProposalSar = this.flowEngine
|
||||
.subFlow(new GetFlow(gameUuid));
|
||||
final GameProposalState gameProposal = (GameProposalState)gameProposalSar.getState().getContractState();
|
||||
|
||||
final UtxoSignedTransaction gameStateRejectTrx = utxoLedgerService.createTransactionBuilder()
|
||||
final UtxoSignedTransaction gameProposalCancelTrx = utxoLedgerService.createTransactionBuilder()
|
||||
.addCommand(command)
|
||||
.addInputState(inputState.getRef())
|
||||
.addSignatories(inputState.getState().getContractState().getParticipants())
|
||||
.setNotary(inputState.getState().getNotaryName())
|
||||
.addInputState(gameProposalSar.getRef())
|
||||
.addSignatories(gameProposal.getParticipants())
|
||||
.setNotary(gameProposalSar.getState().getNotaryName())
|
||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||
.toSignedTransaction();
|
||||
|
||||
gameStateUtxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameStateRejectTrx, command.getObserver(inputState)));
|
||||
utxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameProposalCancelTrx, command.getCounterparty(gameProposal)));
|
||||
|
||||
final View gameStateView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(gameStateUtxoTrxId));
|
||||
.subFlow(new ViewBuilder(utxoTrxId));
|
||||
|
||||
return new FlowResponce(gameStateView, gameStateUtxoTrxId)
|
||||
return new FlowResponce(gameStateView, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
||||
return new FlowResponce(e, gameStateUtxoTrxId)
|
||||
return new FlowResponce(e, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
}
|
||||
|
@ -53,60 +53,63 @@ public class CreateFlow implements ClientStartableFlow{
|
||||
@Suspendable
|
||||
@Override
|
||||
public String call(ClientRequestBody requestBody) {
|
||||
SecureHash gameStateUtxoTrxId = null;
|
||||
SecureHash utxoTrxId = null;
|
||||
|
||||
try {
|
||||
final GameCommand command = new GameCommand(GameCommand.Action.GAME_PROPOSAL_CREATE);
|
||||
|
||||
final GameProposalState newGameProposal = buildGameProposalStateFrom(requestBody);
|
||||
final GameProposalState gameProposal = buildGameProposalStateFrom(requestBody);
|
||||
|
||||
final UtxoSignedTransaction utxoCandidate = utxoLedgerService.createTransactionBuilder()
|
||||
final UtxoSignedTransaction gameProposalCreateTrx = utxoLedgerService.createTransactionBuilder()
|
||||
.addCommand(command)
|
||||
.addOutputState(newGameProposal)
|
||||
.addSignatories(newGameProposal.getParticipants())
|
||||
.addOutputState(gameProposal)
|
||||
.addSignatories(gameProposal.getParticipants())
|
||||
.setNotary(notaryLookup.getNotaryServices().iterator().next().getName())
|
||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||
.toSignedTransaction();
|
||||
|
||||
gameStateUtxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(utxoCandidate, command.getObserver(newGameProposal)));
|
||||
utxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameProposalCreateTrx, command.getCounterparty(gameProposal)));
|
||||
|
||||
final View gameStateView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(gameStateUtxoTrxId));
|
||||
final View gameView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(utxoTrxId));
|
||||
|
||||
return new FlowResponce(gameStateView, gameStateUtxoTrxId)
|
||||
return new FlowResponce(gameView, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
||||
return new FlowResponce(e, gameStateUtxoTrxId)
|
||||
return new FlowResponce(e, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
private GameProposalState buildGameProposalStateFrom(ClientRequestBody requestBody) {
|
||||
CreateFlowArgs args = requestBody.getRequestBodyAs(jsonMarshallingService, CreateFlowArgs.class);
|
||||
final CreateFlowArgs args = requestBody.getRequestBodyAs(jsonMarshallingService, CreateFlowArgs.class);
|
||||
|
||||
Piece.Color opponentColor = Piece.Color.valueOf(args.opponentColor);
|
||||
final Piece.Color opponentColor = Piece.Color.valueOf(args.opponentColor);
|
||||
if (opponentColor == null) {
|
||||
throw new RuntimeException("Allowed values for opponentColor are: "
|
||||
+ Piece.Color.WHITE.name() +", " + Piece.Color.BLACK.name()
|
||||
+ ". Actual value was: " + args.opponentColor);
|
||||
}
|
||||
|
||||
MemberInfo myInfo = memberLookup.myInfo();
|
||||
MemberInfo opponentInfo = requireNonNull(
|
||||
final MemberInfo myInfo = memberLookup.myInfo();
|
||||
final MemberInfo opponentInfo = requireNonNull(
|
||||
memberLookup.lookup(MemberX500Name.parse(args.opponentName)),
|
||||
"MemberLookup can't find opponentName specified in flow arguments: " + args.opponentName
|
||||
);
|
||||
|
||||
final MemberInfo whitePlayerInfo = opponentColor == Piece.Color.WHITE ? opponentInfo : myInfo;
|
||||
final MemberInfo blackPlayerInfo = opponentColor == Piece.Color.BLACK ? opponentInfo : myInfo;
|
||||
|
||||
return new GameProposalState(
|
||||
myInfo.getName(),
|
||||
opponentInfo.getName(),
|
||||
opponentColor,
|
||||
args.message,
|
||||
whitePlayerInfo.getName(),
|
||||
blackPlayerInfo.getName(),
|
||||
myInfo.getName(), // <<--- GameProposal issuer
|
||||
UUID.randomUUID(),
|
||||
args.message,
|
||||
Arrays.asList(myInfo.getLedgerKeys().get(0), opponentInfo.getLedgerKeys().get(0))
|
||||
);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import djmil.cordacheckers.gamestate.FlowResponce;
|
||||
import djmil.cordacheckers.gamestate.GetFlow;
|
||||
import djmil.cordacheckers.gamestate.View;
|
||||
import djmil.cordacheckers.gamestate.ViewBuilder;
|
||||
import djmil.cordacheckers.states.GameProposalState;
|
||||
import djmil.cordacheckers.states.GameState;
|
||||
import net.corda.v5.application.flows.ClientRequestBody;
|
||||
import net.corda.v5.application.flows.ClientStartableFlow;
|
||||
@ -49,36 +50,37 @@ public class RejectFlow implements ClientStartableFlow{
|
||||
@Suspendable
|
||||
@Override
|
||||
public String call(ClientRequestBody requestBody) {
|
||||
SecureHash gameStateUtxoTrxId = null;
|
||||
SecureHash utxoTrxId = null;
|
||||
|
||||
try {
|
||||
final GameCommand command = new GameCommand(GameCommand.Action.GAME_PROPOSAL_REJECT);
|
||||
|
||||
final UUID gameStateUuid = UUID.fromString(requestBody.getRequestBody());
|
||||
final UUID gameUuid = UUID.fromString(requestBody.getRequestBody());
|
||||
|
||||
final StateAndRef<GameState> inputState = this.flowEngine
|
||||
.subFlow(new GetFlow(gameStateUuid));
|
||||
final StateAndRef<GameState> gameProposalSar = this.flowEngine
|
||||
.subFlow(new GetFlow(gameUuid));
|
||||
final GameProposalState gameProposal = (GameProposalState)gameProposalSar.getState().getContractState();
|
||||
|
||||
final UtxoSignedTransaction gameStateRejectTrx = utxoLedgerService.createTransactionBuilder()
|
||||
final UtxoSignedTransaction gameProposalRejectTrx = utxoLedgerService.createTransactionBuilder()
|
||||
.addCommand(command)
|
||||
.addInputState(inputState.getRef())
|
||||
.addSignatories(inputState.getState().getContractState().getParticipants())
|
||||
.setNotary(inputState.getState().getNotaryName())
|
||||
.addInputState(gameProposalSar.getRef())
|
||||
.addSignatories(gameProposal.getParticipants())
|
||||
.setNotary(gameProposalSar.getState().getNotaryName())
|
||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||
.toSignedTransaction();
|
||||
|
||||
gameStateUtxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameStateRejectTrx, command.getObserver(inputState)));
|
||||
utxoTrxId = this.flowEngine
|
||||
.subFlow(new CommitSubFlow(gameProposalRejectTrx, command.getCounterparty(gameProposal)));
|
||||
|
||||
final View gameStateView = this.flowEngine
|
||||
.subFlow(new ViewBuilder(gameStateUtxoTrxId));
|
||||
.subFlow(new ViewBuilder(utxoTrxId));
|
||||
|
||||
return new FlowResponce(gameStateView, gameStateUtxoTrxId)
|
||||
return new FlowResponce(gameStateView, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
||||
return new FlowResponce(e, gameStateUtxoTrxId)
|
||||
return new FlowResponce(e, utxoTrxId)
|
||||
.toJsonEncodedString(jsonMarshallingService);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class CommitSubFlowResponder implements ResponderFlow {
|
||||
UtxoTransactionValidator txValidator = trxToValidate -> {
|
||||
try {
|
||||
final GameCommand gameCommand = getSingleCommand(trxToValidate, GameCommand.class);
|
||||
final GameState gameState = getGameStateFromTransaction(trxToValidate, gameCommand);
|
||||
final GameState gameState = getActualGameStateFromTransaction(trxToValidate, gameCommand);
|
||||
|
||||
checkParticipants(session, gameCommand, gameState);
|
||||
|
||||
@ -72,10 +72,10 @@ public class CommitSubFlowResponder implements ResponderFlow {
|
||||
* @param command
|
||||
* @return the most recent (from perspective of session participants validation) GameState for a given transaction
|
||||
*
|
||||
* @see djmil.cordacheckers.gamestate.ViewBuilder#getGameStateFromTransaction(UtxoLedgerTransaction, GameCommand)
|
||||
* @see djmil.cordacheckers.gamestate.ViewBuilder#getLatestGameStateFromTransaction(UtxoLedgerTransaction, GameCommand)
|
||||
*/
|
||||
@Suspendable
|
||||
GameState getGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) {
|
||||
GameState getActualGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) {
|
||||
switch (command.action) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
return getSingleOutputState(gameStateTransaction, GameProposalState.class);
|
||||
@ -85,10 +85,12 @@ public class CommitSubFlowResponder implements ResponderFlow {
|
||||
case GAME_PROPOSAL_CANCEL:
|
||||
return getSingleInputState(gameStateTransaction, GameProposalState.class);
|
||||
|
||||
case GAME_BOARD_SURRENDER:
|
||||
return getSingleInputState(gameStateTransaction, GameBoardState.class);
|
||||
|
||||
case GAME_BOARD_MOVE:
|
||||
return getSingleOutputState(gameStateTransaction, GameBoardState.class);
|
||||
|
||||
case GAME_BOARD_SURRENDER:
|
||||
case GAME_RESULT_CREATE:
|
||||
return getSingleOutputState(gameStateTransaction, GameResultState.class);
|
||||
}
|
||||
@ -97,22 +99,17 @@ public class CommitSubFlowResponder implements ResponderFlow {
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
void checkParticipants(FlowSession session, GameCommand gameCommand, GameState outputGameState) throws ParticipantException {
|
||||
void checkParticipants(FlowSession session, GameCommand gameCommand, GameState gameState) throws ParticipantException {
|
||||
final var myName = memberLookup.myInfo().getName();
|
||||
final var outputStateConterparty = outputGameState.getCounterpartyName(myName);
|
||||
final var sessionConterparty = session.getCounterparty();
|
||||
|
||||
final var actor = gameCommand.getActor(outputGameState);
|
||||
final var observer = gameCommand.getObserver(outputGameState);
|
||||
final var opponentName = gameState.getOpponentName(myName); // throws NotInvolved
|
||||
final var conterpartyName = session.getCounterparty();
|
||||
final var actorName = gameCommand.getInitiator(gameState);
|
||||
|
||||
if (outputStateConterparty.compareTo(sessionConterparty) != 0)
|
||||
throw new ParticipantException("Counterparty", sessionConterparty, outputStateConterparty);
|
||||
if (conterpartyName.compareTo(opponentName) != 0)
|
||||
throw new ParticipantException("Counterparty", conterpartyName, opponentName);
|
||||
|
||||
if (actor.compareTo(sessionConterparty) != 0)
|
||||
throw new ParticipantException("Actor", sessionConterparty, actor);
|
||||
|
||||
if (observer.compareTo(myName) != 0)
|
||||
throw new ParticipantException("Observer", myName, observer);
|
||||
if (actorName.compareTo(conterpartyName) != 0)
|
||||
throw new ParticipantException("Actor", conterpartyName, actorName);
|
||||
}
|
||||
|
||||
public static class ParticipantException extends Exception {
|
||||
|
@ -10,7 +10,6 @@ import djmil.cordacheckers.states.GameResultState;
|
||||
import djmil.cordacheckers.states.Piece;
|
||||
import net.corda.v5.base.types.MemberX500Name;
|
||||
|
||||
|
||||
// GameBoard from the player's point of view
|
||||
public class View {
|
||||
public static enum Status {
|
||||
@ -51,8 +50,8 @@ public class View {
|
||||
|
||||
public View(View.Status status, GameProposalState gameProposal, MemberX500Name myName) {
|
||||
this.status = status;
|
||||
this.opponentName = gameProposal.getCounterpartyName(myName).getCommonName();
|
||||
this.opponentColor = gameProposal.getCounterpartyColor(myName);
|
||||
this.opponentName = gameProposal.getOpponentName(myName).getCommonName();
|
||||
this.opponentColor = gameProposal.getOpponentColor(myName);
|
||||
this.board = null;
|
||||
this.moveNumber = null;
|
||||
this.previousMove = null;
|
||||
@ -62,8 +61,8 @@ public class View {
|
||||
|
||||
public View(View.Status status, GameBoardState gameBoard, MemberX500Name myName) {
|
||||
this.status = status;
|
||||
this.opponentName = gameBoard.getCounterpartyName(myName).getCommonName();
|
||||
this.opponentColor = gameBoard.getCounterpartyColor(myName);
|
||||
this.opponentName = gameBoard.getOpponentName(myName).getCommonName();
|
||||
this.opponentColor = gameBoard.getOpponentColor(myName);
|
||||
this.board = gameBoard.getBoard();
|
||||
this.moveNumber = gameBoard.getMoveNumber();
|
||||
this.previousMove = null;
|
||||
@ -73,8 +72,8 @@ public class View {
|
||||
|
||||
public View(View.Status status, GameBoardState gameBoard, List<Integer> previousMove, MemberX500Name myName) {
|
||||
this.status = status;
|
||||
this.opponentName = gameBoard.getCounterpartyName(myName).getCommonName();
|
||||
this.opponentColor = gameBoard.getCounterpartyColor(myName);
|
||||
this.opponentName = gameBoard.getOpponentName(myName).getCommonName();
|
||||
this.opponentColor = gameBoard.getOpponentColor(myName);
|
||||
this.board = gameBoard.getBoard();
|
||||
this.moveNumber = gameBoard.getMoveNumber();
|
||||
this.previousMove = previousMove;
|
||||
@ -84,8 +83,8 @@ public class View {
|
||||
|
||||
public View(View.Status status, GameResultState gameResult, MemberX500Name myName) {
|
||||
this.status = status;
|
||||
this.opponentName = gameResult.getCounterpartyName(myName).getCommonName();
|
||||
this.opponentColor = gameResult.getCounterpartyColor(myName);
|
||||
this.opponentName = gameResult.getOpponentName(myName).getCommonName();
|
||||
this.opponentColor = gameResult.getOpponentColor(myName);
|
||||
this.board = null;
|
||||
this.moveNumber = null;
|
||||
this.previousMove = null;
|
||||
|
@ -48,7 +48,7 @@ public class ViewBuilder implements SubFlow<View> {
|
||||
MemberX500Name myName = memberLookup.myInfo().getName();
|
||||
|
||||
final GameCommand command = getSingleCommand(gameStateUtxo, GameCommand.class);
|
||||
final GameState state = getGameStateFromTransaction(gameStateUtxo, command);
|
||||
final GameState state = getLatestGameStateFromTransaction(gameStateUtxo, command);
|
||||
final View.Status viewStatus = action2status(command, state, myName);
|
||||
|
||||
switch (command.action) {
|
||||
@ -81,10 +81,10 @@ public class ViewBuilder implements SubFlow<View> {
|
||||
* @param command
|
||||
* @return the most recent (from perspective of building a GameView) GameState for a given transaction
|
||||
*
|
||||
* @see djmil.cordacheckers.gamestate.CommitSubFlowResponder#getGameStateFromTransaction(UtxoLedgerTransaction, GameCommand)
|
||||
* @see djmil.cordacheckers.gamestate.CommitSubFlowResponder#getActualGameStateFromTransaction(UtxoLedgerTransaction, GameCommand)
|
||||
*/
|
||||
@Suspendable
|
||||
GameState getGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) {
|
||||
GameState getLatestGameStateFromTransaction(UtxoLedgerTransaction gameStateTransaction, GameCommand command) {
|
||||
switch (command.action) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
return getSingleOutputState(gameStateTransaction, GameProposalState.class);
|
||||
@ -107,7 +107,7 @@ public class ViewBuilder implements SubFlow<View> {
|
||||
|
||||
@Suspendable
|
||||
View.Status action2status(GameCommand command, GameState state, MemberX500Name myName) {
|
||||
final boolean myAction = command.getActor(state).compareTo(myName) == 0;
|
||||
final boolean myAction = command.getInitiator(state).compareTo(myName) == 0;
|
||||
|
||||
switch (command.action) {
|
||||
case GAME_PROPOSAL_CREATE:
|
||||
|
Loading…
Reference in New Issue
Block a user