From fee93a2b108d38199d462ad427744494c77ef100 Mon Sep 17 00:00:00 2001 From: djmil Date: Tue, 12 Sep 2023 18:56:07 +0200 Subject: [PATCH] Corda: UtxoLedgerTransactionUtil helper class --- .../cordaclient/CordaClientTest.java | 8 ++-- .../UtxoLedgerTransactionUtil.java | 43 +++++++++++++++++++ .../contracts/GameBoardContract.java | 28 +++++------- .../contracts/GameProposalContract.java | 32 +++++++------- .../java/djmil/cordacheckers/FlowResult.java | 4 +- 5 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 corda/contracts/src/main/java/djmil/cordacheckers/UtxoLedgerTransactionUtil.java diff --git a/backend/src/test/java/djmil/cordacheckers/cordaclient/CordaClientTest.java b/backend/src/test/java/djmil/cordacheckers/cordaclient/CordaClientTest.java index a1e8ddc..78d84ec 100644 --- a/backend/src/test/java/djmil/cordacheckers/cordaclient/CordaClientTest.java +++ b/backend/src/test/java/djmil/cordacheckers/cordaclient/CordaClientTest.java @@ -46,7 +46,7 @@ public class CordaClientTest { } @Test - void testGemeProposalCreate() throws JsonMappingException, JsonProcessingException { + void testGameProposalCreate() throws JsonMappingException, JsonProcessingException { final String gpIssuer = "alice"; final String gpAcquier = "bob"; final Piece.Color gpAcquierColor = Piece.Color.WHITE; @@ -77,7 +77,7 @@ public class CordaClientTest { } @Test - void testGemeProposalReject() throws JsonMappingException, JsonProcessingException { + void testGameProposalReject() throws JsonMappingException, JsonProcessingException { final String gpIssuer = "alice"; final String gpAcquier = "bob"; final Piece.Color gpReceiverColor = Piece.Color.WHITE; @@ -124,7 +124,7 @@ public class CordaClientTest { } @Test - void testGemeProposalAccept() throws JsonMappingException, JsonProcessingException { + void testGameProposalAccept() throws JsonMappingException, JsonProcessingException { final String gpIssuer = "alice"; final String gpAcquier = "bob"; final Piece.Color gpAcquierColor = Piece.Color.WHITE; @@ -179,7 +179,7 @@ public class CordaClientTest { } @Test - void testGemeProposalList() throws JsonMappingException, JsonProcessingException { + void testGameBoardList() throws JsonMappingException, JsonProcessingException { List gbList = cordaClient.gameBoardList( holdingIdentityResolver.getByUsername("bob")); diff --git a/corda/contracts/src/main/java/djmil/cordacheckers/UtxoLedgerTransactionUtil.java b/corda/contracts/src/main/java/djmil/cordacheckers/UtxoLedgerTransactionUtil.java new file mode 100644 index 0000000..3c9e341 --- /dev/null +++ b/corda/contracts/src/main/java/djmil/cordacheckers/UtxoLedgerTransactionUtil.java @@ -0,0 +1,43 @@ +package djmil.cordacheckers; + +import net.corda.v5.ledger.utxo.Command; +import net.corda.v5.ledger.utxo.ContractState; +import net.corda.v5.ledger.utxo.transaction.UtxoLedgerTransaction; + +public class UtxoLedgerTransactionUtil { + private final UtxoLedgerTransaction trx; + + public UtxoLedgerTransactionUtil(UtxoLedgerTransaction trx) { + this.trx = trx; + } + + public T getSingleCommand(Class clazz) { + return trx.getCommands(clazz) + .stream() + .reduce( (a, b) -> {throw new IllegalStateException(trx.getId() +EXPECTED_SINGLE_CLAZZ +clazz);} ) + .get(); + } + + public T getSingleReferenceState(Class clazz) { + return trx.getReferenceStates(clazz) + .stream() + .reduce( (a, b) -> {throw new IllegalStateException(trx.getId() +EXPECTED_SINGLE_CLAZZ +clazz);} ) + .get(); + } + + public T getSingleInputState(Class clazz) { + return trx.getInputStates(clazz) + .stream() + .reduce( (a, b) -> {throw new IllegalStateException(trx.getId() +EXPECTED_SINGLE_CLAZZ +clazz);} ) + .get(); + } + + public T getSingleOutputState(Class clazz) { + return trx.getOutputStates(clazz) + .stream() + .reduce( (a, b) -> {throw new IllegalStateException(trx.getId() +EXPECTED_SINGLE_CLAZZ +clazz);} ) + .get(); + } + + private static String EXPECTED_SINGLE_CLAZZ = ": expected single "; +} diff --git a/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameBoardContract.java b/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameBoardContract.java index ecf393a..a7eb889 100644 --- a/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameBoardContract.java +++ b/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameBoardContract.java @@ -1,10 +1,9 @@ package djmil.cordacheckers.contracts; -import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import djmil.cordacheckers.UtxoLedgerTransactionUtil; import djmil.cordacheckers.states.GameProposalState; import net.corda.v5.base.annotations.Suspendable; import net.corda.v5.base.exceptions.CordaRuntimeException; @@ -17,12 +16,10 @@ public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract { @Override public void verify(UtxoLedgerTransaction trx) { - log.info("GameBoardContract.verify()"); + log.info("GameBoardContract.verify() called"); - final List commandList = trx.getCommands(); - requireThat(commandList.size() == 1, REQUIRE_SINGLE_COMMAND); - - final Command command = commandList.get(0); + final UtxoLedgerTransactionUtil trxUtil = new UtxoLedgerTransactionUtil(trx); + final Command command = trxUtil.getSingleCommand(Command.class); if (command instanceof GameProposalCommand) { log.info("GameBoardContract.verify() as GameProposalCommand "+(GameProposalCommand)command); @@ -39,26 +36,21 @@ public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract { case MOVE: break; } + } else { + throw new CordaRuntimeException(UNKNOWN_COMMAND); } } @Suspendable public static GameProposalState getReferanceGameProposalState(UtxoLedgerTransaction trx) { - final List commandList = trx.getCommands(); - requireThat(commandList.size() == 1, REQUIRE_SINGLE_COMMAND); + final UtxoLedgerTransactionUtil trxUtil = new UtxoLedgerTransactionUtil(trx); + final Command command = trxUtil.getSingleCommand(Command.class); - final Command command = commandList.get(0); if (command instanceof GameProposalCommand && (GameProposalCommand)command == GameProposalCommand.ACCEPT) { - return trx.getInputStates(GameProposalState.class) - .stream() - .reduce( (a, b) -> {throw new IllegalStateException(SINGLE_STATE_EXPECTED);} ) - .get(); + return trxUtil.getSingleInputState(GameProposalState.class); } else if (command instanceof GameBoardCommand) { - return trx.getReferenceStates(GameProposalState.class) - .stream() - .reduce( (a, b) -> {throw new IllegalStateException(SINGLE_STATE_EXPECTED);} ) - .get(); + return trxUtil.getSingleReferenceState(GameProposalState.class); } throw new IllegalStateException(NO_REFERANCE_GAMEPROPOSAL_STATE_FOR_TRXID +trx.getId()); diff --git a/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameProposalContract.java b/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameProposalContract.java index d7a8c6c..553e2b2 100644 --- a/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameProposalContract.java +++ b/corda/contracts/src/main/java/djmil/cordacheckers/contracts/GameProposalContract.java @@ -3,6 +3,7 @@ package djmil.cordacheckers.contracts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import djmil.cordacheckers.UtxoLedgerTransactionUtil; import djmil.cordacheckers.states.GameBoardState; import djmil.cordacheckers.states.GameProposalState; import net.corda.v5.base.exceptions.CordaRuntimeException; @@ -16,42 +17,41 @@ public class GameProposalContract implements net.corda.v5.ledger.utxo.Contract { public void verify(UtxoLedgerTransaction trx) { log.info("GameProposalContract.verify() called"); - requireThat(trx.getCommands().size() == 1, REQUIRE_SINGLE_COMMAND); + final UtxoLedgerTransactionUtil trxUtil = new UtxoLedgerTransactionUtil(trx); + final GameProposalCommand command = trxUtil.getSingleCommand(GameProposalCommand.class); - switch ((trx.getCommands(GameProposalCommand.class).get(0))) { + switch (command) { case CREATE: { requireThat(trx.getInputContractStates().isEmpty(), CREATE_INPUT_STATE); requireThat(trx.getOutputContractStates().size() == 1, CREATE_OUTPUT_STATE); - GameProposalState outputState = trx.getOutputStates(GameProposalState.class).get(0); - requireThat(outputState != null, CREATE_OUTPUT_STATE); + GameProposalState outputState = trxUtil.getSingleOutputState(GameProposalState.class); requireThat(outputState.getAcquierColor() != null, NON_NULL_RECIPIENT_COLOR); break; } - case ACCEPT: + case ACCEPT: { requireThat(trx.getInputContractStates().size() == 1, ACCEPT_INPUT_STATE); requireThat(trx.getOutputContractStates().size() == 1, ACCEPT_OUTPUT_STATE); - GameProposalState inGameProposal = trx.getInputStates(GameProposalState.class).get(0); - requireThat(inGameProposal != null, ACCEPT_INPUT_STATE); - - GameBoardState outGameBoard = trx.getOutputStates(GameBoardState.class).get(0); - requireThat(outGameBoard != null, ACCEPT_INPUT_STATE); + GameProposalState inGameProposal = trxUtil.getSingleInputState(GameProposalState.class); + GameBoardState outGameBoard = trxUtil.getSingleOutputState(GameBoardState.class); requireThat(outGameBoard.getParticipants().containsAll(inGameProposal.getParticipants()), ACCEPT_PARTICIPANTS); - break; + break; } - case REJECT: + case REJECT: { requireThat(trx.getInputContractStates().size() == 1, REJECT_INPUT_STATE); requireThat(trx.getOutputContractStates().isEmpty(), REJECT_OUTPUT_STATE); - requireThat(trx.getInputStates(GameProposalState.class).get(0) != null, REJECT_INPUT_STATE); - break; + + trxUtil.getSingleInputState(GameProposalState.class); + break; } case CANCEL: requireThat(trx.getInputContractStates().size() == 1, CANCEL_INPUT_STATE); requireThat(trx.getOutputContractStates().isEmpty(), CANCEL_OUTPUT_STATE); - requireThat(trx.getInputStates(GameProposalState.class).get(0) != null, CANCEL_INPUT_STATE); + + trxUtil.getSingleInputState(GameProposalState.class); break; default: @@ -60,7 +60,7 @@ public class GameProposalContract implements net.corda.v5.ledger.utxo.Contract { } private void requireThat(boolean asserted, String errorMessage) { - if(!asserted) { + if (!asserted) { throw new CordaRuntimeException("Failed requirement: " + errorMessage); } } diff --git a/corda/workflows/src/main/java/djmil/cordacheckers/FlowResult.java b/corda/workflows/src/main/java/djmil/cordacheckers/FlowResult.java index 47015f9..3903379 100644 --- a/corda/workflows/src/main/java/djmil/cordacheckers/FlowResult.java +++ b/corda/workflows/src/main/java/djmil/cordacheckers/FlowResult.java @@ -5,7 +5,7 @@ import net.corda.v5.crypto.SecureHash; public class FlowResult { public final Object successStatus; - public final String transactionId; + public final SecureHash transactionId; public final String failureStatus; public FlowResult(Object success) { @@ -16,7 +16,7 @@ public class FlowResult { public FlowResult(Object success, SecureHash transactionId) { this.successStatus = success; - this.transactionId = transactionId.toString(); + this.transactionId = transactionId; this.failureStatus = null; }