GameBoard VicrotyFlow
- better error messages - moar GameMove tests - a vicotry condition check - GameContract + participnats vaidation + more accure Major Action checks - automaic Vicotry condition check for Move flow - GameResultCommiter as a sub flow
This commit is contained in:
parent
eb1e7fd93c
commit
e3ca1e0fc0
@ -7,13 +7,13 @@ public interface Rsp <T> {
|
|||||||
public String failureStatus();
|
public String failureStatus();
|
||||||
|
|
||||||
public default T getResponce(RequestBody requestBody) {
|
public default T getResponce(RequestBody requestBody) {
|
||||||
if (failureStatus() != null) {
|
if (failureStatus() == null) {
|
||||||
final String msg = requestBody.flowClassName() +" requestId " +requestBody.clientRequestId() +" has failed: " +failureStatus();
|
System.out.println(requestBody.clientRequestId() +" [OK]");
|
||||||
System.err.println(msg);
|
return successStatus();
|
||||||
throw new RuntimeException(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return successStatus();
|
System.err.println(requestBody.clientRequestId() +" has failed: " +failureStatus());
|
||||||
|
throw new RuntimeException(failureStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,10 @@
|
|||||||
package djmil.cordacheckers.cordaclient.dao.flow.arguments;
|
package djmil.cordacheckers.cordaclient.dao.flow.arguments;
|
||||||
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.GameState;
|
import djmil.cordacheckers.cordaclient.dao.GameState;
|
||||||
import djmil.cordacheckers.cordaclient.dao.flow.RequestBody;
|
|
||||||
|
|
||||||
public record RspGameState(
|
public record RspGameState(
|
||||||
GameState successStatus,
|
GameState successStatus,
|
||||||
String transactionId,
|
String transactionId,
|
||||||
String failureStatus) implements Rsp<GameState> {
|
String failureStatus) implements Rsp<GameState> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public GameState getResponce(RequestBody requestBody) {
|
|
||||||
if (failureStatus() != null) {
|
|
||||||
final String msg = requestBody.flowClassName() +" requestId " +requestBody.clientRequestId() +" has failed";
|
|
||||||
System.err.println(msg +". Reson " +failureStatus +". TransactionId " +transactionId);
|
|
||||||
throw new RuntimeException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("[OK] "+transactionId);
|
|
||||||
return successStatus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -79,12 +79,24 @@ public class GameBoardTests {
|
|||||||
System.out.println("Game UUID " +game.uuid());
|
System.out.println("Game UUID " +game.uuid());
|
||||||
|
|
||||||
final var m0 = cordaClient.gameProposalAccept(hiBlack, game.uuid());
|
final var m0 = cordaClient.gameProposalAccept(hiBlack, game.uuid());
|
||||||
|
assertThat(m0.previousMove()).isNull();
|
||||||
|
assertThat(m0.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
|
||||||
|
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
cordaClient.gameBoardMove(hiBlack, game.uuid(), move(12, 16),
|
cordaClient.gameBoardMove(hiBlack, game.uuid(), move(12, 16),
|
||||||
"Black can not move, since it is opponent's turn");
|
"Black can not move, since it is opponent's turn");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> {
|
||||||
|
cordaClient.gameBoardMove(hiBlack, game.uuid(), move(24, 20),
|
||||||
|
"Black can not move opponent's stone as well");
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> {
|
||||||
|
cordaClient.gameBoardMove(hiWhite, game.uuid(), move(9, 13),
|
||||||
|
"White can not move opponent's stone");
|
||||||
|
});
|
||||||
|
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
cordaClient.gameBoardMove(hiWhite, game.uuid(), move(17, 14),
|
cordaClient.gameBoardMove(hiWhite, game.uuid(), move(17, 14),
|
||||||
"Trying to move an empty tile");
|
"Trying to move an empty tile");
|
||||||
@ -96,11 +108,13 @@ public class GameBoardTests {
|
|||||||
assertThat(m1.board().get(22)).isNull();
|
assertThat(m1.board().get(22)).isNull();
|
||||||
assertThat(m1.board().get(18)).isEqualTo(WHITE_MAN);
|
assertThat(m1.board().get(18)).isEqualTo(WHITE_MAN);
|
||||||
assertThat(m1.moveNumber() == 1);
|
assertThat(m1.moveNumber() == 1);
|
||||||
|
assertThat(m1.previousMove().get(0) == 22);
|
||||||
|
assertThat(m1.previousMove().get(1) == 18);
|
||||||
assertThat(m1.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
|
assertThat(m1.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
|
||||||
|
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
cordaClient.gameBoardMove(hiBlack, game.uuid(), move(12, 13),
|
cordaClient.gameBoardMove(hiBlack, game.uuid(), move(12, 13),
|
||||||
"Prohibitted move shall be rejected");
|
"Prohibited move shall be rejected");
|
||||||
});
|
});
|
||||||
|
|
||||||
final var m2 = cordaClient.gameBoardMove(hiBlack, game.uuid(), move(11, 15), null);
|
final var m2 = cordaClient.gameBoardMove(hiBlack, game.uuid(), move(11, 15), null);
|
||||||
@ -109,6 +123,8 @@ public class GameBoardTests {
|
|||||||
assertThat(m2.board().get(11)).isNull();
|
assertThat(m2.board().get(11)).isNull();
|
||||||
assertThat(m2.board().get(15)).isEqualTo(BLACK_MAN);
|
assertThat(m2.board().get(15)).isEqualTo(BLACK_MAN);
|
||||||
assertThat(m2.moveNumber() == 2);
|
assertThat(m2.moveNumber() == 2);
|
||||||
|
assertThat(m2.previousMove().get(0) == 11);
|
||||||
|
assertThat(m2.previousMove().get(1) == 15);
|
||||||
assertThat(m2.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
|
assertThat(m2.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT);
|
||||||
|
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
|
@ -30,8 +30,8 @@ public class Move {
|
|||||||
return move.apply(board, moveColor);
|
return move.apply(board, moveColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stone.Color apply(Map<Integer, Stone> board, Stone.Color expectedMoveColor) {
|
private Stone.Color apply(Map<Integer, Stone> board, Stone.Color moveColor) {
|
||||||
final Set<Move> mandatoryJumps = getMandatoryJumps(board, expectedMoveColor);
|
final Set<Move> mandatoryJumps = getPossibleJumps(board, moveColor);
|
||||||
if (mandatoryJumps.size() != 0 && !mandatoryJumps.contains(this))
|
if (mandatoryJumps.size() != 0 && !mandatoryJumps.contains(this))
|
||||||
throw new Exception("A mandatory opponent's stone capture must be performed");
|
throw new Exception("A mandatory opponent's stone capture must be performed");
|
||||||
|
|
||||||
@ -39,8 +39,8 @@ public class Move {
|
|||||||
if (movingStone == null)
|
if (movingStone == null)
|
||||||
throw new Exception("An empty starting tile");
|
throw new Exception("An empty starting tile");
|
||||||
|
|
||||||
if (movingStone.getColor() != expectedMoveColor)
|
if (movingStone.getColor() != moveColor)
|
||||||
throw new Exception("Only " +expectedMoveColor.name() +" color is expected to move");
|
throw new Exception("Only " +moveColor.name() +" color is expected to move");
|
||||||
|
|
||||||
final Set<Move> allMoves = movingStone.getMoves(from);
|
final Set<Move> allMoves = movingStone.getMoves(from);
|
||||||
if (!allMoves.contains(this))
|
if (!allMoves.contains(this))
|
||||||
@ -52,16 +52,16 @@ public class Move {
|
|||||||
|
|
||||||
if (isJump()) {
|
if (isJump()) {
|
||||||
final Stone jumpOver = board.remove(this.jumpOver);
|
final Stone jumpOver = board.remove(this.jumpOver);
|
||||||
if (jumpOver == null || jumpOver.getColor() != expectedMoveColor.opposite())
|
if (jumpOver == null || jumpOver.getColor() != moveColor.opposite())
|
||||||
throw new Exception("Must jump over an opponent's stone");
|
throw new Exception("Must jump over an opponent's stone");
|
||||||
|
|
||||||
final Set<Move> chainJumps = movingStone.getJumps(this.to);
|
final Set<Move> chainJumps = movingStone.getJumps(this.to);
|
||||||
chainJumps.removeIf(move -> !move.canJump(board, expectedMoveColor));
|
chainJumps.removeIf(move -> !move.canJump(board, moveColor));
|
||||||
if (chainJumps.size() != 0)
|
if (chainJumps.size() != 0)
|
||||||
return expectedMoveColor; // player must continue his turn
|
return moveColor; // player must continue his turn
|
||||||
}
|
}
|
||||||
|
|
||||||
return expectedMoveColor.opposite(); // player has finished his turn
|
return moveColor.opposite(); // player has finished his turn
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isJump() {
|
boolean isJump() {
|
||||||
@ -69,6 +69,9 @@ public class Move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean canJump(Map<Integer, Stone> board, Stone.Color color) {
|
boolean canJump(Map<Integer, Stone> board, Stone.Color color) {
|
||||||
|
if (!isJump())
|
||||||
|
return false;
|
||||||
|
|
||||||
final Stone jumpStone = board.get(this.from);
|
final Stone jumpStone = board.get(this.from);
|
||||||
if (jumpStone == null || jumpStone.getColor() != color)
|
if (jumpStone == null || jumpStone.getColor() != color)
|
||||||
return false;
|
return false;
|
||||||
@ -83,6 +86,20 @@ public class Move {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canMove(Map<Integer, Stone> board, Stone.Color color) {
|
||||||
|
if (isJump())
|
||||||
|
return canJump(board, color);
|
||||||
|
|
||||||
|
final Stone stepStone = board.get(this.from);
|
||||||
|
if (stepStone == null || stepStone.getColor() != color)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (board.get(this.to) == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static Integer intersection(Set<Integer> a, Set<Integer> b) {
|
static Integer intersection(Set<Integer> a, Set<Integer> b) {
|
||||||
Set<Integer> intersection = new HashSet<Integer>(a);
|
Set<Integer> intersection = new HashSet<Integer>(a);
|
||||||
|
|
||||||
@ -171,7 +188,7 @@ public class Move {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Set<Move> getMandatoryJumps(Map<Integer, Stone> board, Stone.Color color) {
|
static Set<Move> getPossibleJumps(Map<Integer, Stone> board, Stone.Color color) {
|
||||||
Set<Move> res = new HashSet<Move>();
|
Set<Move> res = new HashSet<Move>();
|
||||||
|
|
||||||
for (Map.Entry<Integer, Stone> entry : board.entrySet()) {
|
for (Map.Entry<Integer, Stone> entry : board.entrySet()) {
|
||||||
@ -183,13 +200,30 @@ public class Move {
|
|||||||
|
|
||||||
final Set<Move> jumps = stone.getJumps(from);
|
final Set<Move> jumps = stone.getJumps(from);
|
||||||
jumps.removeIf( move -> !move.canJump(board, color));
|
jumps.removeIf( move -> !move.canJump(board, color));
|
||||||
|
|
||||||
res.addAll(jumps);
|
res.addAll(jumps);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<Move> getPossibleMoves(Map<Integer, Stone> board, Stone.Color color) {
|
||||||
|
Set<Move> res = new HashSet<Move>();
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, Stone> entry : board.entrySet()) {
|
||||||
|
final Integer from = entry.getKey();
|
||||||
|
final Stone stone = entry.getValue();
|
||||||
|
|
||||||
|
if (stone.getColor() != color)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
final Set<Move> moves = stone.getMoves(from);
|
||||||
|
moves.removeIf( move -> !move.canMove(board, color));
|
||||||
|
res.addAll(moves);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
|
@ -3,9 +3,9 @@ package djmil.cordacheckers.contracts;
|
|||||||
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleInputState;
|
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleInputState;
|
||||||
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleOutputState;
|
import static djmil.cordacheckers.contracts.UtxoLedgerTransactionUtil.getSingleOutputState;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import djmil.cordacheckers.checkers.Move;
|
||||||
import djmil.cordacheckers.states.GameBoardState;
|
import djmil.cordacheckers.states.GameBoardState;
|
||||||
import djmil.cordacheckers.states.GameProposalState;
|
import djmil.cordacheckers.states.GameProposalState;
|
||||||
import djmil.cordacheckers.states.GameResultState;
|
import djmil.cordacheckers.states.GameResultState;
|
||||||
@ -91,10 +91,8 @@ public class GameCommand implements Command {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case GAME_BOARD_MOVE:
|
case GAME_BOARD_MOVE:
|
||||||
if (gameState instanceof GameBoardState) {
|
if (gameState instanceof GameBoardState)
|
||||||
final var activePlayer = ((GameBoardState)gameState).getActivePlayerName();
|
return ((GameBoardState)gameState).getIdelPlayerName();
|
||||||
return gameState.getOpponentName(activePlayer);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GAME_BOARD_SURRENDER:
|
case GAME_BOARD_SURRENDER:
|
||||||
@ -114,28 +112,34 @@ public class GameCommand implements Command {
|
|||||||
throw new RuntimeException(action +": unexpected GameState type " +gameState.getClass());
|
throw new RuntimeException(action +": unexpected GameState type " +gameState.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Transaction validation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void validateGameProposalCreate(UtxoLedgerTransaction trx) {
|
public void validateGameProposalCreate(UtxoLedgerTransaction trx) {
|
||||||
requireThat(trx.getInputContractStates().isEmpty(), CREATE_INPUT_STATE);
|
requireThat(trx.getInputContractStates().isEmpty(), CREATE_INPUT_STATE);
|
||||||
requireThat(trx.getOutputContractStates().size() == 1, CREATE_OUTPUT_STATE);
|
requireThat(trx.getOutputContractStates().size() == 1, CREATE_OUTPUT_STATE);
|
||||||
|
|
||||||
final GameProposalState gameProposal = getSingleOutputState(trx, GameProposalState.class);
|
final GameProposalState gameProposal = getSingleOutputState(trx, GameProposalState.class);
|
||||||
|
|
||||||
requireThat(gameProposal.getOpponentName(gameProposal.getIssuerName()).compareTo(gameProposal.getAcquierName()) == 0,
|
/*
|
||||||
|
* Major command logick check
|
||||||
|
*/
|
||||||
|
requireThat(gameProposal.getIssuerName().compareTo(gameProposal.getBlackPlayer()) == 0 ||
|
||||||
|
gameProposal.getIssuerName().compareTo(gameProposal.getWhitePlayer()) == 0,
|
||||||
"GameProposal.Issuer must be either Black or White player");
|
"GameProposal.Issuer must be either Black or White player");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateGameProposalAccept(UtxoLedgerTransaction trx) {
|
public void validateGameProposalAccept(UtxoLedgerTransaction trx) {
|
||||||
requireThat(trx.getInputContractStates().size() == 1, ACCEPT_INPUT_STATE);
|
requireThat(trx.getInputContractStates().size() == 1, ACCEPT_INPUT_STATE);
|
||||||
requireThat(trx.getOutputContractStates().size() == 1, ACCEPT_OUTPUT_STATE);
|
requireThat(trx.getOutputContractStates().size() == 1, ACCEPT_OUTPUT_STATE);
|
||||||
|
|
||||||
final GameProposalState inGameProposal = getSingleInputState(trx, GameProposalState.class);
|
final GameProposalState inGameProposal = getSingleInputState (trx, GameProposalState.class);
|
||||||
final GameBoardState outGameBoard = getSingleOutputState(trx, GameBoardState.class);
|
final GameBoardState outGameBoard = getSingleOutputState(trx, GameBoardState.class);
|
||||||
|
|
||||||
requireThat(inGameProposal.getParticipants().containsAll(outGameBoard.getParticipants()), IN_OUT_PARTICIPANTS);
|
requireThat(outGameBoard.getWhitePlayer().compareTo(inGameProposal.getWhitePlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
|
requireThat(outGameBoard.getBlackPlayer().compareTo(inGameProposal.getBlackPlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
|
requireThat(outGameBoard.getParticipants().containsAll(inGameProposal.getParticipants()), IN_OUT_PARTICIPANTS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Major command logick check
|
||||||
|
*/
|
||||||
requireThat(outGameBoard.getBoard().equals(GameBoardContract.initialBoard), "Bad GameBoard initial state");
|
requireThat(outGameBoard.getBoard().equals(GameBoardContract.initialBoard), "Bad GameBoard initial state");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,47 +157,61 @@ public class GameCommand implements Command {
|
|||||||
getSingleInputState(trx, GameProposalState.class);
|
getSingleInputState(trx, GameProposalState.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.getWhitePlayer(),
|
|
||||||
inGameBoardState.getBlackPlayer())
|
|
||||||
);
|
|
||||||
|
|
||||||
List<MemberX500Name> outActors = new LinkedList<MemberX500Name>(List.of(
|
|
||||||
outGameResultState.getWhitePlayer(),
|
|
||||||
outGameResultState.getBlackPlayer())
|
|
||||||
);
|
|
||||||
|
|
||||||
requireThat(inActors.containsAll(outActors) && outActors.containsAll(inActors), IN_OUT_PARTICIPANTS);
|
|
||||||
|
|
||||||
final GameInfo gameInfo = new GameInfo(trx);
|
|
||||||
final var winnerName = inGameBoardState.getOpponentName(gameInfo.issuer);
|
|
||||||
requireThat(outGameResultState.getWinnerName().compareTo(winnerName) == 0,
|
|
||||||
"Expected winner "+winnerName.getCommonName() +", proposed winner " +outGameResultState.getWinnerName().getCommonName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateGameBoardMove(UtxoLedgerTransaction trx, List<Integer> move) {
|
public void validateGameBoardMove(UtxoLedgerTransaction trx, List<Integer> move) {
|
||||||
requireThat(trx.getInputContractStates().size() == 1, MOVE_INPUT_STATE);
|
requireThat(trx.getInputContractStates().size() == 1, MOVE_INPUT_STATE);
|
||||||
final var inGameBoardState = getSingleInputState(trx, GameBoardState.class);
|
|
||||||
|
|
||||||
requireThat(trx.getOutputContractStates().size() == 1, MOVE_OUTPUT_STATE);
|
requireThat(trx.getOutputContractStates().size() == 1, MOVE_OUTPUT_STATE);
|
||||||
final var outGameBoardState = getSingleOutputState(trx, GameBoardState.class);
|
|
||||||
|
|
||||||
requireThat(inGameBoardState.getWhitePlayer().compareTo(outGameBoardState.getWhitePlayer()) == 0, IN_OUT_PARTICIPANTS);
|
final var inGameBoard = getSingleInputState (trx, GameBoardState.class);
|
||||||
requireThat(inGameBoardState.getBlackPlayer().compareTo(outGameBoardState.getBlackPlayer()) == 0, IN_OUT_PARTICIPANTS);
|
final var outGameBoard = getSingleOutputState(trx, GameBoardState.class);
|
||||||
|
|
||||||
final var newGameBoard = new GameBoardState(inGameBoardState, move, outGameBoardState.getMessage());
|
requireThat(outGameBoard.getWhitePlayer().compareTo(inGameBoard.getWhitePlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
requireThat(outGameBoardState.equals(newGameBoard), "Unexpected output state");
|
requireThat(outGameBoard.getBlackPlayer().compareTo(inGameBoard.getBlackPlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
|
requireThat(outGameBoard.getParticipants().containsAll(inGameBoard.getParticipants()), IN_OUT_PARTICIPANTS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Major command logick check
|
||||||
|
*/
|
||||||
|
final var newGameBoard = new GameBoardState(inGameBoard, move, outGameBoard.getMessage());
|
||||||
|
requireThat(outGameBoard.equals(newGameBoard), "Unexpected output state");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateGameResultCreate(UtxoLedgerTransaction trx) {
|
public void validateGameBoardSurrender(UtxoLedgerTransaction trx) {
|
||||||
throw new RuntimeException("Unimplemented");
|
requireThat(trx.getInputContractStates().size() == 1, SURRENDER_INPUT_STATE);
|
||||||
|
requireThat(trx.getOutputContractStates().size() == 1, SURRENDER_OUTPUT_STATE);
|
||||||
|
|
||||||
|
final var inGameBoard = getSingleInputState (trx, GameBoardState.class);
|
||||||
|
final var outGameResult = getSingleOutputState(trx, GameResultState.class);
|
||||||
|
|
||||||
|
requireThat(outGameResult.getWhitePlayer().compareTo(inGameBoard.getWhitePlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
|
requireThat(outGameResult.getBlackPlayer().compareTo(inGameBoard.getBlackPlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
|
requireThat(outGameResult.getParticipants().containsAll(inGameBoard.getParticipants()), IN_OUT_PARTICIPANTS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Major command logick check
|
||||||
|
*/
|
||||||
|
requireThat(outGameResult.getLooserName().compareTo(outGameResult.getBlackPlayer()) == 0 ||
|
||||||
|
outGameResult.getLooserName().compareTo(outGameResult.getWhitePlayer()) == 0,
|
||||||
|
"Surenderer must be either Black or White player");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateGameBoardVictory(UtxoLedgerTransaction trx) {
|
||||||
|
requireThat(trx.getInputContractStates().size() == 1, VICTORY_INPUT_STATE);
|
||||||
|
requireThat(trx.getOutputContractStates().size() == 1, VICTORY_OUTPUT_STATE);
|
||||||
|
|
||||||
|
final var inGameBoard = getSingleInputState (trx, GameBoardState.class);
|
||||||
|
final var outGameResult = getSingleOutputState(trx, GameResultState.class);
|
||||||
|
|
||||||
|
requireThat(outGameResult.getWhitePlayer().compareTo(inGameBoard.getWhitePlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
|
requireThat(outGameResult.getBlackPlayer().compareTo(inGameBoard.getBlackPlayer()) == 0, IN_OUT_PARTICIPANTS);
|
||||||
|
requireThat(outGameResult.getParticipants().containsAll(inGameBoard.getParticipants()), IN_OUT_PARTICIPANTS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Major command logick check
|
||||||
|
*/
|
||||||
|
final var possibleMoves = Move.getPossibleMoves(inGameBoard.getBoard(), inGameBoard.getActiveColor());
|
||||||
|
requireThat(possibleMoves.isEmpty(), "Victory condition violation");
|
||||||
|
|
||||||
|
requireThat(outGameResult.getWinnerName().compareTo(inGameBoard.getIdelPlayerName()) == 0, "Bad winner name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void requireThat(boolean asserted, String errorMessage) {
|
public static void requireThat(boolean asserted, String errorMessage) {
|
||||||
@ -203,7 +221,7 @@ public class GameCommand implements Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final String REQUIRE_SINGLE_COMMAND = "Require a single command";
|
static final String REQUIRE_SINGLE_COMMAND = "Require a single command";
|
||||||
static final String IN_OUT_PARTICIPANTS = "Input participants should represent output participants";
|
static final String IN_OUT_PARTICIPANTS = "Output participants should include all input participants";
|
||||||
|
|
||||||
static final String CREATE_INPUT_STATE = "Create command should have no input states";
|
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 CREATE_OUTPUT_STATE = "Create command should output exactly one GameProposal state";
|
||||||
@ -224,4 +242,7 @@ public class GameCommand implements Command {
|
|||||||
static final String MOVE_OUTPUT_STATE = "MOVE command should have exactly one GameBoardState output state";
|
static final String MOVE_OUTPUT_STATE = "MOVE command should have exactly one GameBoardState output state";
|
||||||
static final String MOVE_OUT_BOARD = "MOVE command: move checkers rules violation";
|
static final String MOVE_OUT_BOARD = "MOVE command: move checkers rules violation";
|
||||||
static final String MOVE_OUT_COLOR = "MOVE command: moveColor checkers rules violation";
|
static final String MOVE_OUT_COLOR = "MOVE command: moveColor checkers rules violation";
|
||||||
|
|
||||||
|
static final String VICTORY_INPUT_STATE = "VICTORY command should have exactly one GameBoardState input state";
|
||||||
|
static final String VICTORY_OUTPUT_STATE = "VICTORY command should have exactly one GameResultState output state";
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ public class GameInfo {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case GAME_BOARD_SURRENDER:
|
case GAME_BOARD_SURRENDER:
|
||||||
this.state = getSingleOutputState(utxoTrx, GameResultState.class);
|
this.state = getSingleOutputState(utxoTrx, GameResultState.class);
|
||||||
this.issuer = ((GameResultState)this.state).getLooserName();
|
this.issuer = ((GameResultState)this.state).getLooserName();
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
return;
|
return;
|
||||||
|
@ -25,7 +25,7 @@ public class GameResultContract implements net.corda.v5.ledger.utxo.Contract {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case GAME_BOARD_VICTORY:
|
case GAME_BOARD_VICTORY:
|
||||||
command.validateGameResultCreate(trx);
|
command.validateGameBoardVictory(trx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -15,7 +15,7 @@ import net.corda.v5.ledger.utxo.BelongsToContract;
|
|||||||
|
|
||||||
@BelongsToContract(GameBoardContract.class)
|
@BelongsToContract(GameBoardContract.class)
|
||||||
public class GameBoardState extends GameState {
|
public class GameBoardState extends GameState {
|
||||||
private final Stone.Color moveColor;
|
private final Stone.Color activeColor;
|
||||||
private final Integer moveNumber;
|
private final Integer moveNumber;
|
||||||
private final Map<Integer, Stone> board;
|
private final Map<Integer, Stone> board;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ public class GameBoardState extends GameState {
|
|||||||
gameProposalState.gameUuid, gameProposalState.message, gameProposalState.participants);
|
gameProposalState.gameUuid, gameProposalState.message, gameProposalState.participants);
|
||||||
|
|
||||||
this.board = new LinkedHashMap<Integer, Stone>(GameBoardContract.initialBoard);
|
this.board = new LinkedHashMap<Integer, Stone>(GameBoardContract.initialBoard);
|
||||||
this.moveColor = Stone.Color.WHITE;
|
this.activeColor = Stone.Color.WHITE;
|
||||||
this.moveNumber = 0;
|
this.moveNumber = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,26 +33,26 @@ public class GameBoardState extends GameState {
|
|||||||
message, currentGameBoardState.participants);
|
message, currentGameBoardState.participants);
|
||||||
|
|
||||||
this.board = new LinkedHashMap<Integer, Stone>(currentGameBoardState.getBoard());
|
this.board = new LinkedHashMap<Integer, Stone>(currentGameBoardState.getBoard());
|
||||||
this.moveColor = Move.apply(move, this.board, currentGameBoardState.getMoveColor());
|
this.activeColor = Move.apply(move, this.board, currentGameBoardState.getActiveColor());
|
||||||
|
|
||||||
this.moveNumber = (currentGameBoardState.moveColor == this.moveColor)
|
this.moveNumber = (currentGameBoardState.activeColor == this.activeColor)
|
||||||
? currentGameBoardState.getMoveNumber() // current player has not finished his move jet
|
? currentGameBoardState.getMoveNumber() // current player has not finished his move jet
|
||||||
: currentGameBoardState.getMoveNumber() +1;
|
: currentGameBoardState.getMoveNumber() +1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConstructorForDeserialization
|
@ConstructorForDeserialization
|
||||||
public GameBoardState(MemberX500Name whitePlayer, MemberX500Name blackPlayer,
|
public GameBoardState(MemberX500Name whitePlayer, MemberX500Name blackPlayer,
|
||||||
Stone.Color moveColor, Integer moveNumber, Map<Integer, Stone> board, String message,
|
Stone.Color activeColor, Integer moveNumber, Map<Integer, Stone> board, String message,
|
||||||
UUID gameUuid, List<PublicKey> participants) {
|
UUID gameUuid, List<PublicKey> participants) {
|
||||||
super(whitePlayer, blackPlayer, gameUuid, message, participants);
|
super(whitePlayer, blackPlayer, gameUuid, message, participants);
|
||||||
|
|
||||||
this.moveColor = moveColor;
|
this.activeColor = activeColor;
|
||||||
this.moveNumber = moveNumber;
|
this.moveNumber = moveNumber;
|
||||||
this.board = board;
|
this.board = board;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stone.Color getMoveColor() {
|
public Stone.Color getActiveColor() {
|
||||||
return moveColor;
|
return activeColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getMoveNumber() {
|
public Integer getMoveNumber() {
|
||||||
@ -60,7 +60,11 @@ public class GameBoardState extends GameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MemberX500Name getActivePlayerName() {
|
public MemberX500Name getActivePlayerName() {
|
||||||
return moveColor == Stone.Color.WHITE ? whitePlayer : blackPlayer;
|
return activeColor == Stone.Color.WHITE ? whitePlayer : blackPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemberX500Name getIdelPlayerName() {
|
||||||
|
return activeColor == Stone.Color.WHITE ? blackPlayer : whitePlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, Stone> getBoard() {
|
public Map<Integer, Stone> getBoard() {
|
||||||
@ -76,7 +80,7 @@ public class GameBoardState extends GameState {
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
GameBoardState other = (GameBoardState) obj;
|
GameBoardState other = (GameBoardState) obj;
|
||||||
if (moveColor != other.moveColor)
|
if (activeColor != other.activeColor)
|
||||||
return false;
|
return false;
|
||||||
if (moveNumber == null) {
|
if (moveNumber == null) {
|
||||||
if (other.moveNumber != null)
|
if (other.moveNumber != null)
|
||||||
|
@ -21,7 +21,7 @@ public class GameResultState extends GameState {
|
|||||||
this.winnerName = winnerName;
|
this.winnerName = winnerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameResultState(GameBoardState gameBoardState, MemberX500Name winnerName, PublicKey custodianPubicKey) {
|
public GameResultState(MemberX500Name winnerName, GameBoardState gameBoardState, PublicKey custodianPubicKey) {
|
||||||
super(gameBoardState.whitePlayer, gameBoardState.blackPlayer, gameBoardState.gameUuid, null, gameBoardState.participants, custodianPubicKey);
|
super(gameBoardState.whitePlayer, gameBoardState.blackPlayer, gameBoardState.gameUuid, null, gameBoardState.participants, custodianPubicKey);
|
||||||
this.winnerName = winnerName;
|
this.winnerName = winnerName;
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,10 @@ import java.time.Instant;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import djmil.cordacheckers.checkers.Move;
|
||||||
import djmil.cordacheckers.contracts.GameCommand;
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
import djmil.cordacheckers.gameresult.GameResultCommiter;
|
||||||
|
import djmil.cordacheckers.gamestate.CommitTrx;
|
||||||
import djmil.cordacheckers.gamestate.FlowResponce;
|
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||||
import djmil.cordacheckers.gamestate.GetFlow;
|
import djmil.cordacheckers.gamestate.GetFlow;
|
||||||
import djmil.cordacheckers.gamestate.View;
|
import djmil.cordacheckers.gamestate.View;
|
||||||
@ -19,7 +21,9 @@ import net.corda.v5.application.flows.ClientStartableFlow;
|
|||||||
import net.corda.v5.application.flows.CordaInject;
|
import net.corda.v5.application.flows.CordaInject;
|
||||||
import net.corda.v5.application.flows.FlowEngine;
|
import net.corda.v5.application.flows.FlowEngine;
|
||||||
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
||||||
|
import net.corda.v5.application.membership.MemberLookup;
|
||||||
import net.corda.v5.base.annotations.Suspendable;
|
import net.corda.v5.base.annotations.Suspendable;
|
||||||
|
import net.corda.v5.base.types.MemberX500Name;
|
||||||
import net.corda.v5.crypto.SecureHash;
|
import net.corda.v5.crypto.SecureHash;
|
||||||
import net.corda.v5.ledger.utxo.StateAndRef;
|
import net.corda.v5.ledger.utxo.StateAndRef;
|
||||||
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
||||||
@ -38,6 +42,9 @@ public class MoveFlow implements ClientStartableFlow{
|
|||||||
@CordaInject
|
@CordaInject
|
||||||
public FlowEngine flowEngine;
|
public FlowEngine flowEngine;
|
||||||
|
|
||||||
|
@CordaInject
|
||||||
|
public MemberLookup memberLookup;
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
@Override
|
@Override
|
||||||
public String call(ClientRequestBody requestBody) {
|
public String call(ClientRequestBody requestBody) {
|
||||||
@ -48,38 +55,62 @@ public class MoveFlow implements ClientStartableFlow{
|
|||||||
|
|
||||||
final GameCommand command = new GameCommand(args.move);
|
final GameCommand command = new GameCommand(args.move);
|
||||||
|
|
||||||
final StateAndRef<GameState> currntGameBoardSar = this.flowEngine
|
final StateAndRef<GameState> currenrGameSar = this.flowEngine
|
||||||
.subFlow(new GetFlow(args.gameUuid));
|
.subFlow(new GetFlow(args.gameUuid));
|
||||||
|
|
||||||
final GameBoardState newGameBoard = new GameBoardState(
|
final GameBoardState newGameBoard = new GameBoardState(
|
||||||
(GameBoardState)currntGameBoardSar.getState().getContractState(),
|
(GameBoardState)currenrGameSar.getState().getContractState(),
|
||||||
args.move,
|
args.move,
|
||||||
args.message);
|
args.message);
|
||||||
|
|
||||||
final UtxoSignedTransaction gameBoardMoveTrx = utxoLedgerService.createTransactionBuilder()
|
final UtxoSignedTransaction moveTrx = utxoLedgerService.createTransactionBuilder()
|
||||||
.addCommand(command)
|
.addCommand(command)
|
||||||
.addInputState(currntGameBoardSar.getRef())
|
.addInputState(currenrGameSar.getRef())
|
||||||
.addOutputState(newGameBoard)
|
.addOutputState(newGameBoard)
|
||||||
.addSignatories(newGameBoard.getParticipants())
|
.addSignatories(newGameBoard.getParticipants())
|
||||||
.setNotary(currntGameBoardSar.getState().getNotaryName())
|
.setNotary(currenrGameSar.getState().getNotaryName())
|
||||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||||
.toSignedTransaction();
|
.toSignedTransaction();
|
||||||
|
|
||||||
utxoTrxId = this.flowEngine
|
utxoTrxId = this.flowEngine
|
||||||
.subFlow(new CommitSubFlow(gameBoardMoveTrx, command.getCounterparty(currntGameBoardSar)));
|
.subFlow(new CommitTrx(moveTrx, command.getCounterparty(currenrGameSar)));
|
||||||
|
|
||||||
|
if (amIwon(newGameBoard)) {
|
||||||
|
log.info("Opponent has no possible moves. Claim victory!");
|
||||||
|
utxoTrxId = this.flowEngine
|
||||||
|
.subFlow(new GameResultCommiter(
|
||||||
|
newGameBoard.getGameUuid(),
|
||||||
|
new GameCommand(GameCommand.Action.GAME_BOARD_VICTORY)));
|
||||||
|
}
|
||||||
|
|
||||||
final View gameStateView = this.flowEngine
|
final View gameStateView = this.flowEngine
|
||||||
.subFlow(new ViewBuilder(utxoTrxId));
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
|
|
||||||
return new FlowResponce(gameStateView, utxoTrxId)
|
return new FlowResponce(gameStateView, utxoTrxId)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
|
catch (Move.Exception e) {
|
||||||
|
return new FlowResponce(e.getMessage(), utxoTrxId)
|
||||||
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
log.warn(requestBody + " " +e.getClass() +": " +e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
e.printStackTrace(System.out);
|
|
||||||
return new FlowResponce(e, utxoTrxId)
|
return new FlowResponce(e, utxoTrxId)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
boolean amIwon(GameBoardState gameBoard) {
|
||||||
|
final MemberX500Name myName = memberLookup.myInfo().getName();
|
||||||
|
|
||||||
|
if (gameBoard.getActivePlayerName().compareTo(myName) == 0 ||
|
||||||
|
gameBoard.getIdelPlayerName().compareTo(myName) != 0)
|
||||||
|
return false; // a bit of overkill check, but you have to finish your move first
|
||||||
|
|
||||||
|
final var possibleOponnentMoves = Move.getPossibleMoves(gameBoard.getBoard(), gameBoard.getActiveColor());
|
||||||
|
|
||||||
|
return possibleOponnentMoves.isEmpty(); // true, if my opponent has no possible moves
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
package djmil.cordacheckers.gameboard;
|
package djmil.cordacheckers.gameboard;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import djmil.cordacheckers.contracts.GameCommand;
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
import djmil.cordacheckers.gameresult.GameResultBuilder;
|
import djmil.cordacheckers.gameresult.GameResultCommiter;
|
||||||
import djmil.cordacheckers.gameresult.GameResultBuilder.Reason;
|
|
||||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
|
||||||
import djmil.cordacheckers.gamestate.FlowResponce;
|
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||||
import djmil.cordacheckers.gamestate.GetFlow;
|
|
||||||
import djmil.cordacheckers.gamestate.View;
|
import djmil.cordacheckers.gamestate.View;
|
||||||
import djmil.cordacheckers.gamestate.ViewBuilder;
|
import djmil.cordacheckers.gamestate.ViewBuilder;
|
||||||
import djmil.cordacheckers.states.GameState;
|
|
||||||
import net.corda.v5.application.flows.ClientRequestBody;
|
import net.corda.v5.application.flows.ClientRequestBody;
|
||||||
import net.corda.v5.application.flows.ClientStartableFlow;
|
import net.corda.v5.application.flows.ClientStartableFlow;
|
||||||
import net.corda.v5.application.flows.CordaInject;
|
import net.corda.v5.application.flows.CordaInject;
|
||||||
@ -23,9 +17,7 @@ import net.corda.v5.application.flows.FlowEngine;
|
|||||||
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
||||||
import net.corda.v5.base.annotations.Suspendable;
|
import net.corda.v5.base.annotations.Suspendable;
|
||||||
import net.corda.v5.crypto.SecureHash;
|
import net.corda.v5.crypto.SecureHash;
|
||||||
import net.corda.v5.ledger.utxo.StateAndRef;
|
|
||||||
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
||||||
import net.corda.v5.ledger.utxo.transaction.UtxoSignedTransaction;
|
|
||||||
|
|
||||||
public class SurrenderFlow implements ClientStartableFlow{
|
public class SurrenderFlow implements ClientStartableFlow{
|
||||||
|
|
||||||
@ -47,28 +39,10 @@ public class SurrenderFlow implements ClientStartableFlow{
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final GameCommand command = new GameCommand(GameCommand.Action.GAME_BOARD_SURRENDER);
|
final GameCommand command = new GameCommand(GameCommand.Action.GAME_BOARD_SURRENDER);
|
||||||
|
|
||||||
final UUID gameUuid = UUID.fromString(requestBody.getRequestBody());
|
final UUID gameUuid = UUID.fromString(requestBody.getRequestBody());
|
||||||
|
|
||||||
final StateAndRef<GameState> gameBoardSar = this.flowEngine
|
|
||||||
.subFlow(new GetFlow(gameUuid));
|
|
||||||
|
|
||||||
final GameResultBuilder.Result out = this.flowEngine
|
|
||||||
.subFlow(new GameResultBuilder(gameBoardSar, Reason.SURRENDER));
|
|
||||||
|
|
||||||
final UtxoSignedTransaction gameBoardSurrenderTrx = utxoLedgerService.createTransactionBuilder()
|
|
||||||
.addCommand(command)
|
|
||||||
.addInputState(gameBoardSar.getRef())
|
|
||||||
.addOutputState(out.gameResult)
|
|
||||||
.addSignatories(out.gameResult.getParticipants())
|
|
||||||
.setNotary(gameBoardSar.getState().getNotaryName())
|
|
||||||
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
|
||||||
.toSignedTransaction();
|
|
||||||
|
|
||||||
utxoTrxId = this.flowEngine
|
utxoTrxId = this.flowEngine
|
||||||
.subFlow(new CommitSubFlow(gameBoardSurrenderTrx,
|
.subFlow(new GameResultCommiter(gameUuid, command));
|
||||||
command.getCounterparty(out.gameResult),
|
|
||||||
out.custodyName));
|
|
||||||
|
|
||||||
final View gameStateView = this.flowEngine
|
final View gameStateView = this.flowEngine
|
||||||
.subFlow(new ViewBuilder(utxoTrxId));
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
@ -77,8 +51,7 @@ public class SurrenderFlow implements ClientStartableFlow{
|
|||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
e.printStackTrace(System.out);
|
|
||||||
return new FlowResponce(e, utxoTrxId)
|
return new FlowResponce(e, utxoTrxId)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
package djmil.cordacheckers.gameboard;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
|
import djmil.cordacheckers.gameresult.GameResultCommiter;
|
||||||
|
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||||
|
import djmil.cordacheckers.gamestate.View;
|
||||||
|
import djmil.cordacheckers.gamestate.ViewBuilder;
|
||||||
|
import net.corda.v5.application.flows.ClientRequestBody;
|
||||||
|
import net.corda.v5.application.flows.ClientStartableFlow;
|
||||||
|
import net.corda.v5.application.flows.CordaInject;
|
||||||
|
import net.corda.v5.application.flows.FlowEngine;
|
||||||
|
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
||||||
|
import net.corda.v5.base.annotations.Suspendable;
|
||||||
|
import net.corda.v5.crypto.SecureHash;
|
||||||
|
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
||||||
|
|
||||||
|
public class VictoryFlow implements ClientStartableFlow {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(VictoryFlow.class);
|
||||||
|
|
||||||
|
@CordaInject
|
||||||
|
public JsonMarshallingService jsonMarshallingService;
|
||||||
|
|
||||||
|
@CordaInject
|
||||||
|
public UtxoLedgerService utxoLedgerService;
|
||||||
|
|
||||||
|
@CordaInject
|
||||||
|
public FlowEngine flowEngine;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Suspendable
|
||||||
|
public String call(ClientRequestBody requestBody) {
|
||||||
|
SecureHash utxoTrxId = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final UUID gameUuid = UUID.fromString(requestBody.getRequestBody());
|
||||||
|
final GameCommand command = new GameCommand(GameCommand.Action.GAME_BOARD_VICTORY);
|
||||||
|
|
||||||
|
utxoTrxId = this.flowEngine
|
||||||
|
.subFlow(new GameResultCommiter(gameUuid, command));
|
||||||
|
|
||||||
|
final View gameStateView = this.flowEngine
|
||||||
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
|
|
||||||
|
return new FlowResponce(gameStateView, utxoTrxId)
|
||||||
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
|
return new FlowResponce(e, utxoTrxId)
|
||||||
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -8,7 +8,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import djmil.cordacheckers.contracts.GameCommand;
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
import djmil.cordacheckers.gamestate.CommitTrx;
|
||||||
import djmil.cordacheckers.gamestate.FlowResponce;
|
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||||
import djmil.cordacheckers.gamestate.GetFlow;
|
import djmil.cordacheckers.gamestate.GetFlow;
|
||||||
import djmil.cordacheckers.gamestate.View;
|
import djmil.cordacheckers.gamestate.View;
|
||||||
@ -56,7 +56,7 @@ public class AcceptFlow implements ClientStartableFlow{
|
|||||||
|
|
||||||
final GameBoardState gameBoard = new GameBoardState(gameProposal); // <<-- accepted
|
final GameBoardState gameBoard = new GameBoardState(gameProposal); // <<-- accepted
|
||||||
|
|
||||||
final UtxoSignedTransaction gameProposalAcceptTrx = utxoLedgerService.createTransactionBuilder()
|
final UtxoSignedTransaction acceptTrx = utxoLedgerService.createTransactionBuilder()
|
||||||
.addCommand(command)
|
.addCommand(command)
|
||||||
.addInputState(gameProposalSar.getRef())
|
.addInputState(gameProposalSar.getRef())
|
||||||
.addOutputState(gameBoard)
|
.addOutputState(gameBoard)
|
||||||
@ -66,7 +66,7 @@ public class AcceptFlow implements ClientStartableFlow{
|
|||||||
.toSignedTransaction();
|
.toSignedTransaction();
|
||||||
|
|
||||||
utxoTrxId = this.flowEngine
|
utxoTrxId = this.flowEngine
|
||||||
.subFlow(new CommitSubFlow(gameProposalAcceptTrx, command.getCounterparty(gameProposal)));
|
.subFlow(new CommitTrx(acceptTrx, command.getCounterparty(gameProposal)));
|
||||||
|
|
||||||
final View gameView = this.flowEngine
|
final View gameView = this.flowEngine
|
||||||
.subFlow(new ViewBuilder(utxoTrxId));
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
@ -75,8 +75,7 @@ public class AcceptFlow implements ClientStartableFlow{
|
|||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
e.printStackTrace(System.out);
|
|
||||||
return new FlowResponce(e, utxoTrxId)
|
return new FlowResponce(e, utxoTrxId)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import djmil.cordacheckers.contracts.GameCommand;
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
import djmil.cordacheckers.gamestate.CommitTrx;
|
||||||
import djmil.cordacheckers.gamestate.FlowResponce;
|
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||||
import djmil.cordacheckers.gamestate.GetFlow;
|
import djmil.cordacheckers.gamestate.GetFlow;
|
||||||
import djmil.cordacheckers.gamestate.View;
|
import djmil.cordacheckers.gamestate.View;
|
||||||
@ -62,7 +62,7 @@ public class CancelFlow implements ClientStartableFlow{
|
|||||||
.toSignedTransaction();
|
.toSignedTransaction();
|
||||||
|
|
||||||
utxoTrxId = this.flowEngine
|
utxoTrxId = this.flowEngine
|
||||||
.subFlow(new CommitSubFlow(gameProposalCancelTrx, command.getCounterparty(gameProposal)));
|
.subFlow(new CommitTrx(gameProposalCancelTrx, command.getCounterparty(gameProposal)));
|
||||||
|
|
||||||
final View gameStateView = this.flowEngine
|
final View gameStateView = this.flowEngine
|
||||||
.subFlow(new ViewBuilder(utxoTrxId));
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
@ -71,7 +71,7 @@ public class CancelFlow implements ClientStartableFlow{
|
|||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
return new FlowResponce(e, utxoTrxId)
|
return new FlowResponce(e, utxoTrxId)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import djmil.cordacheckers.checkers.Stone;
|
import djmil.cordacheckers.checkers.Stone;
|
||||||
import djmil.cordacheckers.contracts.GameCommand;
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
import djmil.cordacheckers.gamestate.CommitTrx;
|
||||||
import djmil.cordacheckers.gamestate.FlowResponce;
|
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||||
import djmil.cordacheckers.gamestate.View;
|
import djmil.cordacheckers.gamestate.View;
|
||||||
import djmil.cordacheckers.gamestate.ViewBuilder;
|
import djmil.cordacheckers.gamestate.ViewBuilder;
|
||||||
@ -69,7 +69,7 @@ public class CreateFlow implements ClientStartableFlow{
|
|||||||
.toSignedTransaction();
|
.toSignedTransaction();
|
||||||
|
|
||||||
utxoTrxId = this.flowEngine
|
utxoTrxId = this.flowEngine
|
||||||
.subFlow(new CommitSubFlow(gameProposalCreateTrx, command.getCounterparty(gameProposal)));
|
.subFlow(new CommitTrx(gameProposalCreateTrx, command.getCounterparty(gameProposal)));
|
||||||
|
|
||||||
final View gameView = this.flowEngine
|
final View gameView = this.flowEngine
|
||||||
.subFlow(new ViewBuilder(utxoTrxId));
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
@ -78,7 +78,7 @@ public class CreateFlow implements ClientStartableFlow{
|
|||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
return new FlowResponce(e, utxoTrxId)
|
return new FlowResponce(e, utxoTrxId)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import djmil.cordacheckers.contracts.GameCommand;
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
import djmil.cordacheckers.gamestate.CommitTrx;
|
||||||
import djmil.cordacheckers.gamestate.FlowResponce;
|
import djmil.cordacheckers.gamestate.FlowResponce;
|
||||||
import djmil.cordacheckers.gamestate.GetFlow;
|
import djmil.cordacheckers.gamestate.GetFlow;
|
||||||
import djmil.cordacheckers.gamestate.View;
|
import djmil.cordacheckers.gamestate.View;
|
||||||
@ -70,7 +70,7 @@ public class RejectFlow implements ClientStartableFlow{
|
|||||||
.toSignedTransaction();
|
.toSignedTransaction();
|
||||||
|
|
||||||
utxoTrxId = this.flowEngine
|
utxoTrxId = this.flowEngine
|
||||||
.subFlow(new CommitSubFlow(gameProposalRejectTrx, command.getCounterparty(gameProposal)));
|
.subFlow(new CommitTrx(gameProposalRejectTrx, command.getCounterparty(gameProposal)));
|
||||||
|
|
||||||
final View gameStateView = this.flowEngine
|
final View gameStateView = this.flowEngine
|
||||||
.subFlow(new ViewBuilder(utxoTrxId));
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
@ -79,7 +79,7 @@ public class RejectFlow implements ClientStartableFlow{
|
|||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
return new FlowResponce(e, utxoTrxId)
|
return new FlowResponce(e, utxoTrxId)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
package djmil.cordacheckers.gameresult;
|
|
||||||
|
|
||||||
import djmil.cordacheckers.states.GameBoardState;
|
|
||||||
import djmil.cordacheckers.states.GameResultState;
|
|
||||||
import djmil.cordacheckers.states.GameState;
|
|
||||||
import net.corda.v5.application.flows.CordaInject;
|
|
||||||
import net.corda.v5.application.flows.SubFlow;
|
|
||||||
import net.corda.v5.application.membership.MemberLookup;
|
|
||||||
import net.corda.v5.base.annotations.Suspendable;
|
|
||||||
import net.corda.v5.base.types.MemberX500Name;
|
|
||||||
import net.corda.v5.ledger.utxo.StateAndRef;
|
|
||||||
import net.corda.v5.membership.MemberInfo;
|
|
||||||
|
|
||||||
public class GameResultBuilder implements SubFlow<GameResultBuilder.Result> {
|
|
||||||
public class Result {
|
|
||||||
final public GameResultState gameResult;
|
|
||||||
final public MemberX500Name custodyName;
|
|
||||||
|
|
||||||
public Result(GameResultState gameResult, MemberX500Name custodyName){
|
|
||||||
this.gameResult = gameResult;
|
|
||||||
this.custodyName = custodyName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum Reason {
|
|
||||||
VICTORY,
|
|
||||||
SURRENDER
|
|
||||||
}
|
|
||||||
|
|
||||||
private final GameBoardState gameBoard;
|
|
||||||
private final Reason reason;
|
|
||||||
|
|
||||||
public GameResultBuilder(StateAndRef<GameState> gameBoardSar, Reason reason) {
|
|
||||||
this.gameBoard = (GameBoardState)gameBoardSar.getState().getContractState();
|
|
||||||
this.reason = reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CordaInject
|
|
||||||
public MemberLookup memberLookup;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Suspendable
|
|
||||||
public Result call() {
|
|
||||||
final MemberInfo custodiaInfo = findCustodian();
|
|
||||||
|
|
||||||
return new Result(
|
|
||||||
new GameResultState(gameBoard, winnerName(), custodiaInfo.getLedgerKeys().get(0)),
|
|
||||||
custodiaInfo.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suspendable
|
|
||||||
MemberInfo findCustodian() {
|
|
||||||
return memberLookup.lookup()
|
|
||||||
.stream()
|
|
||||||
.filter(m -> m.getName().getOrganizationUnit().equals("Custodian") )
|
|
||||||
.reduce((a,b) -> {throw new IllegalStateException("Multiple Custodian VNodes");})
|
|
||||||
.orElseThrow( () -> new IllegalStateException("No Custodian VNode found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suspendable
|
|
||||||
MemberX500Name winnerName() {
|
|
||||||
final MemberX500Name myName = memberLookup.myInfo().getName();
|
|
||||||
|
|
||||||
switch(reason) {
|
|
||||||
case VICTORY:
|
|
||||||
return myName;
|
|
||||||
case SURRENDER:
|
|
||||||
return gameBoard.getOpponentName(myName);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException("Bad reason");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,99 @@
|
|||||||
|
package djmil.cordacheckers.gameresult;
|
||||||
|
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import djmil.cordacheckers.contracts.GameCommand;
|
||||||
|
import djmil.cordacheckers.gamestate.CommitTrx;
|
||||||
|
import djmil.cordacheckers.gamestate.GetFlow;
|
||||||
|
import djmil.cordacheckers.states.GameBoardState;
|
||||||
|
import djmil.cordacheckers.states.GameResultState;
|
||||||
|
import djmil.cordacheckers.states.GameState;
|
||||||
|
import net.corda.v5.application.flows.CordaInject;
|
||||||
|
import net.corda.v5.application.flows.FlowEngine;
|
||||||
|
import net.corda.v5.application.flows.SubFlow;
|
||||||
|
import net.corda.v5.application.membership.MemberLookup;
|
||||||
|
import net.corda.v5.base.annotations.Suspendable;
|
||||||
|
import net.corda.v5.base.types.MemberX500Name;
|
||||||
|
import net.corda.v5.crypto.SecureHash;
|
||||||
|
import net.corda.v5.ledger.utxo.StateAndRef;
|
||||||
|
import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
||||||
|
import net.corda.v5.ledger.utxo.transaction.UtxoSignedTransaction;
|
||||||
|
import net.corda.v5.membership.MemberInfo;
|
||||||
|
|
||||||
|
public class GameResultCommiter implements SubFlow<SecureHash> {
|
||||||
|
|
||||||
|
private final UUID gameUuid;
|
||||||
|
private final GameCommand command;
|
||||||
|
|
||||||
|
public GameResultCommiter(UUID gameUuid, GameCommand command) {
|
||||||
|
this.gameUuid = gameUuid;
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CordaInject
|
||||||
|
public FlowEngine flowEngine;
|
||||||
|
|
||||||
|
@CordaInject
|
||||||
|
public MemberLookup memberLookup;
|
||||||
|
|
||||||
|
@CordaInject
|
||||||
|
public UtxoLedgerService utxoLedgerService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Suspendable
|
||||||
|
public SecureHash call() {
|
||||||
|
final MemberInfo custodianInfo = findCustodian();
|
||||||
|
|
||||||
|
final StateAndRef<GameState> gameBoardSar = this.flowEngine
|
||||||
|
.subFlow(new GetFlow(this.gameUuid));
|
||||||
|
final GameBoardState gameBoard = (GameBoardState)gameBoardSar.getState().getContractState();
|
||||||
|
|
||||||
|
final GameResultState gameResult = gameResultBuilder(gameBoard, custodianInfo);
|
||||||
|
|
||||||
|
final UtxoSignedTransaction gameResultTrx = utxoLedgerService.createTransactionBuilder()
|
||||||
|
.addCommand(this.command)
|
||||||
|
.addInputState(gameBoardSar.getRef())
|
||||||
|
.addOutputState(gameResult)
|
||||||
|
.addSignatories(gameResult.getParticipants())
|
||||||
|
.setNotary(gameBoardSar.getState().getNotaryName())
|
||||||
|
.setTimeWindowUntil(Instant.now().plusMillis(Duration.ofDays(1).toMillis()))
|
||||||
|
.toSignedTransaction();
|
||||||
|
|
||||||
|
return this.flowEngine.subFlow(
|
||||||
|
new CommitTrx(gameResultTrx,
|
||||||
|
command.getCounterparty(gameResult),
|
||||||
|
custodianInfo.getName()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
MemberInfo findCustodian() {
|
||||||
|
return memberLookup.lookup()
|
||||||
|
.stream()
|
||||||
|
.filter(m -> m.getName().getOrganizationUnit().equals("Custodian") )
|
||||||
|
.reduce((a,b) -> {throw new IllegalStateException("Multiple Custodian VNodes");})
|
||||||
|
.orElseThrow( () -> new IllegalStateException("No Custodian VNode found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
GameResultState gameResultBuilder(GameBoardState gameBoard, MemberInfo custodiaInfo) {
|
||||||
|
final PublicKey custodianPublicKey = custodiaInfo.getLedgerKeys().get(0);
|
||||||
|
final MemberX500Name myName = memberLookup.myInfo().getName();
|
||||||
|
|
||||||
|
switch(this.command.getAction()) {
|
||||||
|
case GAME_BOARD_VICTORY:
|
||||||
|
return new GameResultState(myName, // i'm a winner
|
||||||
|
gameBoard, custodianPublicKey);
|
||||||
|
|
||||||
|
case GAME_BOARD_SURRENDER:
|
||||||
|
return new GameResultState(gameBoard.getOpponentName(myName), // me surrender to
|
||||||
|
gameBoard, custodianPublicKey);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("GameResult: bad reason");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,20 +20,20 @@ import net.corda.v5.ledger.utxo.UtxoLedgerService;
|
|||||||
import net.corda.v5.ledger.utxo.transaction.UtxoSignedTransaction;
|
import net.corda.v5.ledger.utxo.transaction.UtxoSignedTransaction;
|
||||||
|
|
||||||
@InitiatingFlow(protocol = "gamestate-commit")
|
@InitiatingFlow(protocol = "gamestate-commit")
|
||||||
public class CommitSubFlow implements SubFlow<SecureHash> {
|
public class CommitTrx implements SubFlow<SecureHash> {
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(CommitSubFlow.class);
|
private final static Logger log = LoggerFactory.getLogger(CommitTrx.class);
|
||||||
private final UtxoSignedTransaction utxTrxCandidate;
|
private final UtxoSignedTransaction utxTrxCandidate;
|
||||||
private final MemberX500Name counterpartyName;
|
private final MemberX500Name counterpartyName;
|
||||||
private final MemberX500Name custodyName;
|
private final MemberX500Name custodyName;
|
||||||
|
|
||||||
public CommitSubFlow(UtxoSignedTransaction signedTransaction, MemberX500Name counterpartyName) {
|
public CommitTrx(UtxoSignedTransaction signedTransaction, MemberX500Name counterpartyName) {
|
||||||
this.utxTrxCandidate = signedTransaction;
|
this.utxTrxCandidate = signedTransaction;
|
||||||
this.counterpartyName = counterpartyName;
|
this.counterpartyName = counterpartyName;
|
||||||
this.custodyName = null;
|
this.custodyName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommitSubFlow(UtxoSignedTransaction signedTransaction, MemberX500Name counterpartyName, MemberX500Name custodyName) {
|
public CommitTrx(UtxoSignedTransaction signedTransaction, MemberX500Name counterpartyName, MemberX500Name custodyName) {
|
||||||
this.utxTrxCandidate = signedTransaction;
|
this.utxTrxCandidate = signedTransaction;
|
||||||
this.counterpartyName = counterpartyName;
|
this.counterpartyName = counterpartyName;
|
||||||
this.custodyName = custodyName;
|
this.custodyName = custodyName;
|
@ -17,9 +17,9 @@ import net.corda.v5.ledger.utxo.transaction.UtxoLedgerTransaction;
|
|||||||
import net.corda.v5.ledger.utxo.transaction.UtxoTransactionValidator;
|
import net.corda.v5.ledger.utxo.transaction.UtxoTransactionValidator;
|
||||||
|
|
||||||
@InitiatedBy(protocol = "gamestate-commit")
|
@InitiatedBy(protocol = "gamestate-commit")
|
||||||
public class CommitSubFlowResponder implements ResponderFlow {
|
public class CommitTrxResponder implements ResponderFlow {
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(CommitSubFlowResponder.class);
|
private final static Logger log = LoggerFactory.getLogger(CommitTrxResponder.class);
|
||||||
|
|
||||||
@CordaInject
|
@CordaInject
|
||||||
public MemberLookup memberLookup;
|
public MemberLookup memberLookup;
|
@ -20,6 +20,12 @@ public class FlowResponce {
|
|||||||
this.failureStatus = exception.toString();
|
this.failureStatus = exception.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FlowResponce(String exceptionMessage, SecureHash transactionId) {
|
||||||
|
this.successStatus = null;
|
||||||
|
this.transactionId = transactionId;
|
||||||
|
this.failureStatus = exceptionMessage;
|
||||||
|
}
|
||||||
|
|
||||||
public String toJsonEncodedString(JsonMarshallingService jsonMarshallingService) {
|
public String toJsonEncodedString(JsonMarshallingService jsonMarshallingService) {
|
||||||
return jsonMarshallingService.format(this);
|
return jsonMarshallingService.format(this);
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,9 @@ public class GetFlow implements ClientStartableFlow, SubFlow<StateAndRef<GameSta
|
|||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
return new FlowResponce(e, gameStateUtxoTrxId).toJsonEncodedString(jsonMarshallingService);
|
return new FlowResponce(e, gameStateUtxoTrxId)
|
||||||
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public class ListFlow implements ClientStartableFlow {
|
|||||||
return new ListFlowResponce(gameStateViewList)
|
return new ListFlowResponce(gameStateViewList)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
log.warn(requestBody + " [ERROR] " +e.toString());
|
||||||
return new ListFlowResponce(e)
|
return new ListFlowResponce(e)
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
.toJsonEncodedString(jsonMarshallingService);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user