Compare commits
No commits in common. "8971462c74e785a98780f9eb4d5ed8a25303cd0c" and "ada353ce2f21e1dc99ce156b3c93335158f81e4f" have entirely different histories.
8971462c74
...
ada353ce2f
@ -19,7 +19,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import djmil.cordacheckers.cordaclient.dao.GameState;
|
import djmil.cordacheckers.cordaclient.dao.GameState;
|
||||||
import djmil.cordacheckers.cordaclient.dao.HoldingIdentity;
|
import djmil.cordacheckers.cordaclient.dao.HoldingIdentity;
|
||||||
import djmil.cordacheckers.cordaclient.dao.Piece;
|
import djmil.cordacheckers.cordaclient.dao.Piece;
|
||||||
import djmil.cordacheckers.cordaclient.dao.Rank;
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.VirtualNode;
|
import djmil.cordacheckers.cordaclient.dao.VirtualNode;
|
||||||
import djmil.cordacheckers.cordaclient.dao.VirtualNodeList;
|
import djmil.cordacheckers.cordaclient.dao.VirtualNodeList;
|
||||||
import djmil.cordacheckers.cordaclient.dao.flow.RequestBody;
|
import djmil.cordacheckers.cordaclient.dao.flow.RequestBody;
|
||||||
@ -30,7 +29,6 @@ import djmil.cordacheckers.cordaclient.dao.flow.arguments.ReqGameBoardMove;
|
|||||||
import djmil.cordacheckers.cordaclient.dao.flow.arguments.ReqGameProposalCreate;
|
import djmil.cordacheckers.cordaclient.dao.flow.arguments.ReqGameProposalCreate;
|
||||||
import djmil.cordacheckers.cordaclient.dao.flow.arguments.RspGameState;
|
import djmil.cordacheckers.cordaclient.dao.flow.arguments.RspGameState;
|
||||||
import djmil.cordacheckers.cordaclient.dao.flow.arguments.RspGameStateList;
|
import djmil.cordacheckers.cordaclient.dao.flow.arguments.RspGameStateList;
|
||||||
import djmil.cordacheckers.cordaclient.dao.flow.arguments.RspRankList;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class CordaClient {
|
public class CordaClient {
|
||||||
@ -60,17 +58,6 @@ public class CordaClient {
|
|||||||
).virtualNodes();
|
).virtualNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// use custodian holding identity to get ranking table of all players
|
|
||||||
public List<Rank> fetchRanking(HoldingIdentity holdingIdentity) {
|
|
||||||
final RequestBody requestBody = new RequestBody(
|
|
||||||
"ranking-" +UUID.randomUUID(),
|
|
||||||
"djmil.cordacheckers.gameresult.RankingFlow",
|
|
||||||
new Req());
|
|
||||||
|
|
||||||
return cordaFlowExecute(holdingIdentity, requestBody, RspRankList.class)
|
|
||||||
.getResponce(requestBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param holdingIdentity
|
* @param holdingIdentity
|
||||||
* @return list of unconsumed (active) GameStateViews
|
* @return list of unconsumed (active) GameStateViews
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
package djmil.cordacheckers.cordaclient.dao;
|
|
||||||
|
|
||||||
public record Rank(
|
|
||||||
String name,
|
|
||||||
Integer gamesPlayed,
|
|
||||||
Integer gamesWon
|
|
||||||
) {
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package djmil.cordacheckers.cordaclient.dao.flow.arguments;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.Rank;
|
|
||||||
|
|
||||||
public record RspRankList(
|
|
||||||
List<Rank> successStatus,
|
|
||||||
String failureStatus) implements Rsp<List<Rank>> {
|
|
||||||
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
package djmil.cordacheckers;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
|
|
||||||
import djmil.cordacheckers.user.HoldingIdentityResolver;
|
|
||||||
|
|
||||||
@SpringBootTest
|
|
||||||
public class HoldingIdentityResolverTests {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
HoldingIdentityResolver holdingIdentityResolver;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The test is expecting that CSDE static-network-config.json to look like stated below.
|
|
||||||
* Important bits:
|
|
||||||
* - the contents of 'CN', 'OU', 'O' fields
|
|
||||||
* - there shall be only one Custodian
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"x500Name" : "CN=Alice, OU=Player, O=Checkers, L=Zug, C=CH",
|
|
||||||
"cpi" : "CordaCheckers"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x500Name" : "CN=Bob, OU=Player, O=Checkers, L=Kyiv, C=UA",
|
|
||||||
"cpi" : "CordaCheckers"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x500Name" : "CN=Charlie, OU=Player, O=Checkers, L=London, C=GB",
|
|
||||||
"cpi" : "CordaCheckers"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x500Name" : "CN=Kumar, OU=Custodian, O=Checkers, L=Mumbai, C=IN",
|
|
||||||
"cpi" : "CordaCheckers"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x500Name" : "CN=NotaryRep1, OU=Test Dept, O=R3, L=London, C=GB",
|
|
||||||
"cpi" : "NotaryServer",
|
|
||||||
"serviceX500Name": "CN=NotaryService, OU=Test Dept, O=R3, L=London, C=GB"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPlayer() {
|
|
||||||
assertDoesNotThrow( () -> {
|
|
||||||
holdingIdentityResolver.getByUsername("alice");
|
|
||||||
holdingIdentityResolver.getByUsername("BOB");
|
|
||||||
holdingIdentityResolver.getByUsername("Charlie");
|
|
||||||
});
|
|
||||||
|
|
||||||
assertThat(holdingIdentityResolver.getByUsername("SomeRundomName")).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCustodian() {
|
|
||||||
assertThat(holdingIdentityResolver.getByUsername("Kumar")).isNull();
|
|
||||||
assertThat(holdingIdentityResolver.getCustodian()).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -60,4 +60,40 @@ public class GameBoardTests {
|
|||||||
assertThat(winnerGameView.status()).isEqualByComparingTo(Status.GAME_RESULT_YOU_WON);
|
assertThat(winnerGameView.status()).isEqualByComparingTo(Status.GAME_RESULT_YOU_WON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// void testGameBoardMove() throws JsonMappingException, JsonProcessingException, InvalidNameException {
|
||||||
|
// final var hiAlice = holdingIdentityResolver.getByUsername("alice");
|
||||||
|
// final var hiBob = holdingIdentityResolver.getByUsername("bob");
|
||||||
|
// final var bobColor = Piece.Color.WHITE;
|
||||||
|
|
||||||
|
// final UUID gpUuid = cordaClient.gameProposalCreate(
|
||||||
|
// hiAlice, hiBob,
|
||||||
|
// bobColor, "GameBoard MOVE test"
|
||||||
|
// );
|
||||||
|
|
||||||
|
// System.out.println("New GameProposal UUID "+ gpUuid);
|
||||||
|
|
||||||
|
// final GameBoard gbState = cordaClient.gameProposalAccept(
|
||||||
|
// hiBob, gpUuid
|
||||||
|
// );
|
||||||
|
|
||||||
|
// System.out.println("New GameBoard UUID "+ gbState.gameUuid());
|
||||||
|
|
||||||
|
// assertThatThrownBy(() -> { // Alice can not move, since it is Bob's turn
|
||||||
|
// cordaClient.gameBoardMove(
|
||||||
|
// hiAlice, gbState.gameUuid(),
|
||||||
|
// Arrays.asList(1, 2));
|
||||||
|
// });
|
||||||
|
|
||||||
|
// final GameBoard gameBoard = cordaClient.gameBoardMove(
|
||||||
|
// hiBob, gbState.gameUuid(), Arrays.asList(1, 2));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private <T extends GameState> T findByUuid(List<T> statesList, UUID uuid) {
|
||||||
|
// for (T state : statesList) {
|
||||||
|
// if (state.uuid().compareTo(uuid) == 0)
|
||||||
|
// return state;
|
||||||
|
// };
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
package djmil.cordacheckers.cordaclient;
|
package djmil.cordacheckers.cordaclient;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.naming.InvalidNameException;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.GameState;
|
import djmil.cordacheckers.cordaclient.dao.GameState;
|
||||||
import djmil.cordacheckers.cordaclient.dao.Piece;
|
import djmil.cordacheckers.cordaclient.dao.VirtualNode;
|
||||||
import djmil.cordacheckers.user.HoldingIdentityResolver;
|
import djmil.cordacheckers.user.HoldingIdentityResolver;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@ -19,12 +25,15 @@ public class GameStateTests {
|
|||||||
@Autowired
|
@Autowired
|
||||||
HoldingIdentityResolver holdingIdentityResolver;
|
HoldingIdentityResolver holdingIdentityResolver;
|
||||||
|
|
||||||
final String issuer = "alice";
|
@Test
|
||||||
final String acquier = "bob";
|
void testGetVirtualNodeList() throws InvalidNameException {
|
||||||
final Piece.Color acquierColor = Piece.Color.WHITE;
|
List<VirtualNode> vNodes = cordaClient.getVirtualNodeList();
|
||||||
|
|
||||||
|
assertThat(vNodes.size()).isEqualTo(5); // default vNode config for CSDE
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testList() {
|
void testList() throws JsonProcessingException {
|
||||||
List<GameState> gsList = cordaClient.gameStateList(
|
List<GameState> gsList = cordaClient.gameStateList(
|
||||||
holdingIdentityResolver.getByUsername("bob"));
|
holdingIdentityResolver.getByUsername("bob"));
|
||||||
|
|
||||||
@ -32,7 +41,7 @@ public class GameStateTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGet() {
|
void testGet() throws JsonProcessingException {
|
||||||
GameState gameStateView = cordaClient.gameStateGet(
|
GameState gameStateView = cordaClient.gameStateGet(
|
||||||
holdingIdentityResolver.getByUsername("bob"),
|
holdingIdentityResolver.getByUsername("bob"),
|
||||||
UUID.fromString("cf357d0a-8f64-4599-b9b5-d263163812d4")
|
UUID.fromString("cf357d0a-8f64-4599-b9b5-d263163812d4")
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
package djmil.cordacheckers.cordaclient;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.GameState;
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.GameState.Status;
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.Piece;
|
|
||||||
import djmil.cordacheckers.cordaclient.dao.Rank;
|
|
||||||
import djmil.cordacheckers.user.HoldingIdentityResolver;
|
|
||||||
|
|
||||||
@SpringBootTest
|
|
||||||
public class RankingTests {
|
|
||||||
@Autowired
|
|
||||||
CordaClient cordaClient;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
HoldingIdentityResolver holdingIdentityResolver;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGlobalRanking() {
|
|
||||||
final var hiCustodian = holdingIdentityResolver.getCustodian();
|
|
||||||
final List<Rank> liderboard1 = cordaClient.fetchRanking(hiCustodian);
|
|
||||||
|
|
||||||
final var hiWinner = holdingIdentityResolver.getByUsername("Charlie");
|
|
||||||
final var hiLooser = holdingIdentityResolver.getByUsername("Bob");
|
|
||||||
|
|
||||||
final GameState game = cordaClient.gameProposalCreate(
|
|
||||||
hiWinner, hiLooser, Piece.Color.WHITE, "GameBoard GLOBAL_RANKING test");
|
|
||||||
|
|
||||||
cordaClient.gameProposalAccept(hiLooser, game.uuid());
|
|
||||||
cordaClient.gameBoardSurrender(hiLooser, game.uuid());
|
|
||||||
|
|
||||||
final List<Rank> liderboard2 = cordaClient.fetchRanking(hiCustodian);
|
|
||||||
|
|
||||||
System.out.println(liderboard1);
|
|
||||||
System.out.println(liderboard2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testIndividualRanking() {
|
|
||||||
final var hiCustodian = holdingIdentityResolver.getByUsername("Bob");
|
|
||||||
final List<Rank> liderboard = cordaClient.fetchRanking(hiCustodian);
|
|
||||||
System.out.println(liderboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -21,8 +21,8 @@ public class GameResultState extends GameState {
|
|||||||
this.winnerName = winnerName;
|
this.winnerName = winnerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameResultState(GameBoardState gameBoardState, MemberX500Name winnerName, PublicKey custodianPubicKey) {
|
public GameResultState(GameBoardState gameBoardState, MemberX500Name winnerName) {
|
||||||
super(gameBoardState.whitePlayer, gameBoardState.blackPlayer, gameBoardState.gameUuid, null, gameBoardState.participants, custodianPubicKey);
|
super(gameBoardState.whitePlayer, gameBoardState.blackPlayer, gameBoardState.gameUuid, null, gameBoardState.participants);
|
||||||
this.winnerName = winnerName;
|
this.winnerName = winnerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package djmil.cordacheckers.states;
|
package djmil.cordacheckers.states;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -26,18 +25,6 @@ public abstract class GameState implements ContractState {
|
|||||||
this.participants = participants;
|
this.participants = participants;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameState(MemberX500Name whitePlayer, MemberX500Name blackPlayer, UUID gameUuid,
|
|
||||||
String message, List<PublicKey> participants, PublicKey additionalParticipand) {
|
|
||||||
this.whitePlayer = whitePlayer;
|
|
||||||
this.blackPlayer = blackPlayer;
|
|
||||||
this.gameUuid = gameUuid;
|
|
||||||
this.message = message;
|
|
||||||
|
|
||||||
var deepCopy = new LinkedList<>(participants);
|
|
||||||
deepCopy.add(additionalParticipand);
|
|
||||||
this.participants = deepCopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MemberX500Name getWhitePlayer() {
|
public MemberX500Name getWhitePlayer() {
|
||||||
return whitePlayer;
|
return whitePlayer;
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,13 @@ 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.GameResultBuilder.Reason;
|
|
||||||
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
import djmil.cordacheckers.gamestate.CommitSubFlow;
|
||||||
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;
|
||||||
import djmil.cordacheckers.gamestate.ViewBuilder;
|
import djmil.cordacheckers.gamestate.ViewBuilder;
|
||||||
|
import djmil.cordacheckers.states.GameBoardState;
|
||||||
|
import djmil.cordacheckers.states.GameResultState;
|
||||||
import djmil.cordacheckers.states.GameState;
|
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;
|
||||||
@ -23,6 +23,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.application.membership.MemberLookup;
|
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.common.NotaryLookup;
|
import net.corda.v5.ledger.common.NotaryLookup;
|
||||||
import net.corda.v5.ledger.utxo.StateAndRef;
|
import net.corda.v5.ledger.utxo.StateAndRef;
|
||||||
@ -56,27 +57,24 @@ 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 gameStateUuid = UUID.fromString(requestBody.getRequestBody());
|
||||||
|
|
||||||
final StateAndRef<GameState> gameBoardSar = this.flowEngine
|
final StateAndRef<GameState> inputStateSar = this.flowEngine
|
||||||
.subFlow(new GetFlow(gameUuid));
|
.subFlow(new GetFlow(gameStateUuid));
|
||||||
|
|
||||||
final GameResultBuilder.Result out = this.flowEngine
|
final GameResultState outputState = prepareGameResultState(inputStateSar);
|
||||||
.subFlow(new GameResultBuilder(gameBoardSar, Reason.SURRENDER));
|
|
||||||
|
|
||||||
final UtxoSignedTransaction gameBoardSurrenderTrx = utxoLedgerService.createTransactionBuilder()
|
final UtxoSignedTransaction gameBoardSurrenderTrx = utxoLedgerService.createTransactionBuilder()
|
||||||
.addCommand(command)
|
.addCommand(command)
|
||||||
.addInputState(gameBoardSar.getRef())
|
.addInputState(inputStateSar.getRef())
|
||||||
.addOutputState(out.gameResult)
|
.addOutputState(outputState)
|
||||||
.addSignatories(out.gameResult.getParticipants())
|
.addSignatories(outputState.getParticipants())
|
||||||
.setNotary(gameBoardSar.getState().getNotaryName())
|
.setNotary(inputStateSar.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(gameBoardSurrenderTrx,
|
.subFlow(new CommitSubFlow(gameBoardSurrenderTrx, command.getCounterparty(inputStateSar)));
|
||||||
command.getCounterparty(gameBoardSar),
|
|
||||||
out.custodyName));
|
|
||||||
|
|
||||||
final View gameStateView = this.flowEngine
|
final View gameStateView = this.flowEngine
|
||||||
.subFlow(new ViewBuilder(utxoTrxId));
|
.subFlow(new ViewBuilder(utxoTrxId));
|
||||||
@ -92,4 +90,15 @@ public class SurrenderFlow implements ClientStartableFlow{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
GameResultState prepareGameResultState(StateAndRef<GameState> gameStateSar) {
|
||||||
|
final GameState gameState = gameStateSar.getState().getContractState();
|
||||||
|
final GameBoardState gameBoard = (GameBoardState) gameState;
|
||||||
|
|
||||||
|
final MemberX500Name myName = memberLookup.myInfo().getName();
|
||||||
|
final MemberX500Name winnerName = gameBoard.getOpponentName(myName);
|
||||||
|
|
||||||
|
return new GameResultState(gameBoard, winnerName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package djmil.cordacheckers.gameresult;
|
|
||||||
|
|
||||||
public class Rank {
|
|
||||||
public final String name;
|
|
||||||
public final Integer gamesPlayed;
|
|
||||||
public final Integer gamesWon;
|
|
||||||
|
|
||||||
// Serialisation service requires a default constructor
|
|
||||||
Rank() {
|
|
||||||
name = null;
|
|
||||||
gamesPlayed = null;
|
|
||||||
gamesWon = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rank(String name, Integer gamesPlayed, Integer gamesWon) {
|
|
||||||
this.name = name;
|
|
||||||
this.gamesPlayed = gamesPlayed;
|
|
||||||
this.gamesWon = gamesWon;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
package djmil.cordacheckers.gameresult;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import djmil.cordacheckers.states.GameResultState;
|
|
||||||
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.ledger.utxo.UtxoLedgerService;
|
|
||||||
|
|
||||||
public class RankingFlow implements ClientStartableFlow {
|
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(RankingFlow.class);
|
|
||||||
|
|
||||||
@CordaInject
|
|
||||||
public UtxoLedgerService utxoLedgerService;
|
|
||||||
|
|
||||||
@CordaInject
|
|
||||||
public JsonMarshallingService jsonMarshallingService;
|
|
||||||
|
|
||||||
@CordaInject
|
|
||||||
public FlowEngine flowEngine;
|
|
||||||
|
|
||||||
@Suspendable
|
|
||||||
@Override
|
|
||||||
public String call(ClientRequestBody requestBody) {
|
|
||||||
try {
|
|
||||||
final List<GameResultState> gameStateResutList = getGameResultsList();
|
|
||||||
|
|
||||||
Map<String, Integer> won = new HashMap<>();
|
|
||||||
for (GameResultState gs : gameStateResutList) {
|
|
||||||
final var winner = gs.getWinnerName().getCommonName();
|
|
||||||
won.put(winner, won.getOrDefault(winner, 0) +1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Integer> played = new HashMap<>(won);
|
|
||||||
for (GameResultState gs : gameStateResutList) {
|
|
||||||
final var looseer = gs.getLooserName().getCommonName();
|
|
||||||
played.put(looseer, played.getOrDefault(looseer, 0) +1);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Rank> board = new LinkedList<Rank>();
|
|
||||||
for (String name : played.keySet()) {
|
|
||||||
board.add(new Rank(name, played.getOrDefault(name, 0), won.getOrDefault(name, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RankingFlowResponce(board)
|
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Exception during processing " + requestBody + " request: " + e.getMessage());
|
|
||||||
return new RankingFlowResponce(e)
|
|
||||||
.toJsonEncodedString(jsonMarshallingService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suspendable
|
|
||||||
List<GameResultState> getGameResultsList() {
|
|
||||||
return utxoLedgerService
|
|
||||||
.findUnconsumedStatesByType(GameResultState.class)
|
|
||||||
.stream()
|
|
||||||
.map( stateAndRef -> stateAndRef.getState().getContractState() )
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package djmil.cordacheckers.gameresult;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.corda.v5.application.marshalling.JsonMarshallingService;
|
|
||||||
|
|
||||||
public class RankingFlowResponce {
|
|
||||||
public final List<Rank> successStatus;
|
|
||||||
public final String failureStatus;
|
|
||||||
|
|
||||||
public RankingFlowResponce(List<Rank> success) {
|
|
||||||
this.successStatus = success;
|
|
||||||
this.failureStatus = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RankingFlowResponce(Exception exception) {
|
|
||||||
this.successStatus = null;
|
|
||||||
this.failureStatus = exception.getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toJsonEncodedString(JsonMarshallingService jsonMarshallingService) {
|
|
||||||
return jsonMarshallingService.format(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package djmil.cordacheckers.gamestate;
|
package djmil.cordacheckers.gamestate;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -10,7 +9,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import net.corda.v5.application.flows.CordaInject;
|
import net.corda.v5.application.flows.CordaInject;
|
||||||
import net.corda.v5.application.flows.InitiatingFlow;
|
import net.corda.v5.application.flows.InitiatingFlow;
|
||||||
import net.corda.v5.application.flows.SubFlow;
|
import net.corda.v5.application.flows.SubFlow;
|
||||||
import net.corda.v5.application.membership.MemberLookup;
|
|
||||||
import net.corda.v5.application.messaging.FlowMessaging;
|
import net.corda.v5.application.messaging.FlowMessaging;
|
||||||
import net.corda.v5.application.messaging.FlowSession;
|
import net.corda.v5.application.messaging.FlowSession;
|
||||||
import net.corda.v5.base.annotations.Suspendable;
|
import net.corda.v5.base.annotations.Suspendable;
|
||||||
@ -25,18 +23,10 @@ public class CommitSubFlow implements SubFlow<SecureHash> {
|
|||||||
private final static Logger log = LoggerFactory.getLogger(CommitSubFlow.class);
|
private final static Logger log = LoggerFactory.getLogger(CommitSubFlow.class);
|
||||||
private final UtxoSignedTransaction utxTrxCandidate;
|
private final UtxoSignedTransaction utxTrxCandidate;
|
||||||
private final MemberX500Name counterpartyName;
|
private final MemberX500Name counterpartyName;
|
||||||
private final MemberX500Name custodyName;
|
|
||||||
|
|
||||||
public CommitSubFlow(UtxoSignedTransaction signedTransaction, MemberX500Name counterpartyName) {
|
public CommitSubFlow(UtxoSignedTransaction signedTransaction, MemberX500Name counterpartyName) {
|
||||||
this.utxTrxCandidate = signedTransaction;
|
this.utxTrxCandidate = signedTransaction;
|
||||||
this.counterpartyName = counterpartyName;
|
this.counterpartyName = counterpartyName;
|
||||||
this.custodyName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommitSubFlow(UtxoSignedTransaction signedTransaction, MemberX500Name counterpartyName, MemberX500Name custodyName) {
|
|
||||||
this.utxTrxCandidate = signedTransaction;
|
|
||||||
this.counterpartyName = counterpartyName;
|
|
||||||
this.custodyName = custodyName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CordaInject
|
@CordaInject
|
||||||
@ -45,25 +35,19 @@ public class CommitSubFlow implements SubFlow<SecureHash> {
|
|||||||
@CordaInject
|
@CordaInject
|
||||||
public FlowMessaging flowMessaging;
|
public FlowMessaging flowMessaging;
|
||||||
|
|
||||||
@CordaInject
|
|
||||||
public MemberLookup memberLookup;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Suspendable
|
@Suspendable
|
||||||
public SecureHash call() {
|
public SecureHash call() {
|
||||||
log.info("GameState commit started");
|
log.info("GameState commit started");
|
||||||
|
|
||||||
|
final FlowSession session = flowMessaging.initiateFlow(this.counterpartyName);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calls the Corda provided finalise() function which gather signatures from the counterparty,
|
* Calls the Corda provided finalise() function which gather signatures from the counterparty,
|
||||||
* notarises the transaction and persists the transaction to each party's vault.
|
* notarises the transaction and persists the transaction to each party's vault.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
final FlowSession session = flowMessaging.initiateFlow(this.counterpartyName);
|
final List<FlowSession> sessionsList = Arrays.asList(session);
|
||||||
List<FlowSession> sessionsList = new LinkedList<FlowSession>(Arrays.asList(session));
|
|
||||||
|
|
||||||
if (custodyName != null) {
|
|
||||||
sessionsList.add(flowMessaging.initiateFlow(custodyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
final SecureHash trxId = ledgerService
|
final SecureHash trxId = ledgerService
|
||||||
.finalize(this.utxTrxCandidate, sessionsList)
|
.finalize(this.utxTrxCandidate, sessionsList)
|
||||||
|
@ -100,18 +100,16 @@ public class CommitSubFlowResponder implements ResponderFlow {
|
|||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
void checkParticipants(FlowSession session, GameCommand gameCommand, GameState gameState) throws ParticipantException {
|
void checkParticipants(FlowSession session, GameCommand gameCommand, GameState gameState) throws ParticipantException {
|
||||||
|
final var myName = memberLookup.myInfo().getName();
|
||||||
|
final var opponentName = gameState.getOpponentName(myName); // throws NotInvolved
|
||||||
final var conterpartyName = session.getCounterparty();
|
final var conterpartyName = session.getCounterparty();
|
||||||
final var actorName = gameCommand.getInitiator(gameState);
|
final var actorName = gameCommand.getInitiator(gameState);
|
||||||
if (actorName.compareTo(conterpartyName) != 0)
|
|
||||||
throw new ParticipantException("Actor", conterpartyName, actorName);
|
|
||||||
|
|
||||||
final var myName = memberLookup.myInfo().getName();
|
|
||||||
if (myName.getOrganizationUnit().equals("Custodian"))
|
|
||||||
return; // Custodian shall not validate state's counterparty
|
|
||||||
|
|
||||||
final var opponentName = gameState.getOpponentName(myName); // throws NotInvolved
|
|
||||||
if (conterpartyName.compareTo(opponentName) != 0)
|
if (conterpartyName.compareTo(opponentName) != 0)
|
||||||
throw new ParticipantException("Counterparty", conterpartyName, opponentName);
|
throw new ParticipantException("Counterparty", conterpartyName, opponentName);
|
||||||
|
|
||||||
|
if (actorName.compareTo(conterpartyName) != 0)
|
||||||
|
throw new ParticipantException("Actor", conterpartyName, actorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ParticipantException extends Exception {
|
public static class ParticipantException extends Exception {
|
||||||
|
Loading…
Reference in New Issue
Block a user