Corda: UtxoLedgerTransactionUtil helper class

This commit is contained in:
djmil 2023-09-12 18:56:07 +02:00
parent fdfcd711a7
commit fee93a2b10
5 changed files with 75 additions and 40 deletions

View File

@ -46,7 +46,7 @@ public class CordaClientTest {
} }
@Test @Test
void testGemeProposalCreate() throws JsonMappingException, JsonProcessingException { void testGameProposalCreate() throws JsonMappingException, JsonProcessingException {
final String gpIssuer = "alice"; final String gpIssuer = "alice";
final String gpAcquier = "bob"; final String gpAcquier = "bob";
final Piece.Color gpAcquierColor = Piece.Color.WHITE; final Piece.Color gpAcquierColor = Piece.Color.WHITE;
@ -77,7 +77,7 @@ public class CordaClientTest {
} }
@Test @Test
void testGemeProposalReject() throws JsonMappingException, JsonProcessingException { void testGameProposalReject() throws JsonMappingException, JsonProcessingException {
final String gpIssuer = "alice"; final String gpIssuer = "alice";
final String gpAcquier = "bob"; final String gpAcquier = "bob";
final Piece.Color gpReceiverColor = Piece.Color.WHITE; final Piece.Color gpReceiverColor = Piece.Color.WHITE;
@ -124,7 +124,7 @@ public class CordaClientTest {
} }
@Test @Test
void testGemeProposalAccept() throws JsonMappingException, JsonProcessingException { void testGameProposalAccept() throws JsonMappingException, JsonProcessingException {
final String gpIssuer = "alice"; final String gpIssuer = "alice";
final String gpAcquier = "bob"; final String gpAcquier = "bob";
final Piece.Color gpAcquierColor = Piece.Color.WHITE; final Piece.Color gpAcquierColor = Piece.Color.WHITE;
@ -179,7 +179,7 @@ public class CordaClientTest {
} }
@Test @Test
void testGemeProposalList() throws JsonMappingException, JsonProcessingException { void testGameBoardList() throws JsonMappingException, JsonProcessingException {
List <GameBoard> gbList = cordaClient.gameBoardList( List <GameBoard> gbList = cordaClient.gameBoardList(
holdingIdentityResolver.getByUsername("bob")); holdingIdentityResolver.getByUsername("bob"));

View File

@ -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 extends Command> T getSingleCommand(Class<T> clazz) {
return trx.getCommands(clazz)
.stream()
.reduce( (a, b) -> {throw new IllegalStateException(trx.getId() +EXPECTED_SINGLE_CLAZZ +clazz);} )
.get();
}
public <T extends ContractState> T getSingleReferenceState(Class<T> clazz) {
return trx.getReferenceStates(clazz)
.stream()
.reduce( (a, b) -> {throw new IllegalStateException(trx.getId() +EXPECTED_SINGLE_CLAZZ +clazz);} )
.get();
}
public <T extends ContractState> T getSingleInputState(Class<T> clazz) {
return trx.getInputStates(clazz)
.stream()
.reduce( (a, b) -> {throw new IllegalStateException(trx.getId() +EXPECTED_SINGLE_CLAZZ +clazz);} )
.get();
}
public <T extends ContractState> T getSingleOutputState(Class<T> 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 ";
}

View File

@ -1,10 +1,9 @@
package djmil.cordacheckers.contracts; package djmil.cordacheckers.contracts;
import java.util.List;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import djmil.cordacheckers.UtxoLedgerTransactionUtil;
import djmil.cordacheckers.states.GameProposalState; import djmil.cordacheckers.states.GameProposalState;
import net.corda.v5.base.annotations.Suspendable; import net.corda.v5.base.annotations.Suspendable;
import net.corda.v5.base.exceptions.CordaRuntimeException; import net.corda.v5.base.exceptions.CordaRuntimeException;
@ -17,12 +16,10 @@ public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract {
@Override @Override
public void verify(UtxoLedgerTransaction trx) { public void verify(UtxoLedgerTransaction trx) {
log.info("GameBoardContract.verify()"); log.info("GameBoardContract.verify() called");
final List<Command> commandList = trx.getCommands(); final UtxoLedgerTransactionUtil trxUtil = new UtxoLedgerTransactionUtil(trx);
requireThat(commandList.size() == 1, REQUIRE_SINGLE_COMMAND); final Command command = trxUtil.getSingleCommand(Command.class);
final Command command = commandList.get(0);
if (command instanceof GameProposalCommand) { if (command instanceof GameProposalCommand) {
log.info("GameBoardContract.verify() as GameProposalCommand "+(GameProposalCommand)command); log.info("GameBoardContract.verify() as GameProposalCommand "+(GameProposalCommand)command);
@ -39,26 +36,21 @@ public class GameBoardContract implements net.corda.v5.ledger.utxo.Contract {
case MOVE: case MOVE:
break; break;
} }
} else {
throw new CordaRuntimeException(UNKNOWN_COMMAND);
} }
} }
@Suspendable @Suspendable
public static GameProposalState getReferanceGameProposalState(UtxoLedgerTransaction trx) { public static GameProposalState getReferanceGameProposalState(UtxoLedgerTransaction trx) {
final List<Command> commandList = trx.getCommands(); final UtxoLedgerTransactionUtil trxUtil = new UtxoLedgerTransactionUtil(trx);
requireThat(commandList.size() == 1, REQUIRE_SINGLE_COMMAND); final Command command = trxUtil.getSingleCommand(Command.class);
final Command command = commandList.get(0);
if (command instanceof GameProposalCommand && (GameProposalCommand)command == GameProposalCommand.ACCEPT) { if (command instanceof GameProposalCommand && (GameProposalCommand)command == GameProposalCommand.ACCEPT) {
return trx.getInputStates(GameProposalState.class) return trxUtil.getSingleInputState(GameProposalState.class);
.stream()
.reduce( (a, b) -> {throw new IllegalStateException(SINGLE_STATE_EXPECTED);} )
.get();
} else } else
if (command instanceof GameBoardCommand) { if (command instanceof GameBoardCommand) {
return trx.getReferenceStates(GameProposalState.class) return trxUtil.getSingleReferenceState(GameProposalState.class);
.stream()
.reduce( (a, b) -> {throw new IllegalStateException(SINGLE_STATE_EXPECTED);} )
.get();
} }
throw new IllegalStateException(NO_REFERANCE_GAMEPROPOSAL_STATE_FOR_TRXID +trx.getId()); throw new IllegalStateException(NO_REFERANCE_GAMEPROPOSAL_STATE_FOR_TRXID +trx.getId());

View File

@ -3,6 +3,7 @@ package djmil.cordacheckers.contracts;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import djmil.cordacheckers.UtxoLedgerTransactionUtil;
import djmil.cordacheckers.states.GameBoardState; import djmil.cordacheckers.states.GameBoardState;
import djmil.cordacheckers.states.GameProposalState; import djmil.cordacheckers.states.GameProposalState;
import net.corda.v5.base.exceptions.CordaRuntimeException; 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) { public void verify(UtxoLedgerTransaction trx) {
log.info("GameProposalContract.verify() called"); 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: { case CREATE: {
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);
GameProposalState outputState = trx.getOutputStates(GameProposalState.class).get(0); GameProposalState outputState = trxUtil.getSingleOutputState(GameProposalState.class);
requireThat(outputState != null, CREATE_OUTPUT_STATE);
requireThat(outputState.getAcquierColor() != null, NON_NULL_RECIPIENT_COLOR); requireThat(outputState.getAcquierColor() != null, NON_NULL_RECIPIENT_COLOR);
break; } break; }
case ACCEPT: case ACCEPT: {
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);
GameProposalState inGameProposal = trx.getInputStates(GameProposalState.class).get(0); GameProposalState inGameProposal = trxUtil.getSingleInputState(GameProposalState.class);
requireThat(inGameProposal != null, ACCEPT_INPUT_STATE); GameBoardState outGameBoard = trxUtil.getSingleOutputState(GameBoardState.class);
GameBoardState outGameBoard = trx.getOutputStates(GameBoardState.class).get(0);
requireThat(outGameBoard != null, ACCEPT_INPUT_STATE);
requireThat(outGameBoard.getParticipants().containsAll(inGameProposal.getParticipants()), ACCEPT_PARTICIPANTS); requireThat(outGameBoard.getParticipants().containsAll(inGameProposal.getParticipants()), ACCEPT_PARTICIPANTS);
break; break; }
case REJECT: case REJECT: {
requireThat(trx.getInputContractStates().size() == 1, REJECT_INPUT_STATE); requireThat(trx.getInputContractStates().size() == 1, REJECT_INPUT_STATE);
requireThat(trx.getOutputContractStates().isEmpty(), REJECT_OUTPUT_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: case CANCEL:
requireThat(trx.getInputContractStates().size() == 1, CANCEL_INPUT_STATE); requireThat(trx.getInputContractStates().size() == 1, CANCEL_INPUT_STATE);
requireThat(trx.getOutputContractStates().isEmpty(), CANCEL_OUTPUT_STATE); requireThat(trx.getOutputContractStates().isEmpty(), CANCEL_OUTPUT_STATE);
requireThat(trx.getInputStates(GameProposalState.class).get(0) != null, CANCEL_INPUT_STATE);
trxUtil.getSingleInputState(GameProposalState.class);
break; break;
default: default:
@ -60,7 +60,7 @@ public class GameProposalContract implements net.corda.v5.ledger.utxo.Contract {
} }
private void requireThat(boolean asserted, String errorMessage) { private void requireThat(boolean asserted, String errorMessage) {
if(!asserted) { if (!asserted) {
throw new CordaRuntimeException("Failed requirement: " + errorMessage); throw new CordaRuntimeException("Failed requirement: " + errorMessage);
} }
} }

View File

@ -5,7 +5,7 @@ import net.corda.v5.crypto.SecureHash;
public class FlowResult { public class FlowResult {
public final Object successStatus; public final Object successStatus;
public final String transactionId; public final SecureHash transactionId;
public final String failureStatus; public final String failureStatus;
public FlowResult(Object success) { public FlowResult(Object success) {
@ -16,7 +16,7 @@ public class FlowResult {
public FlowResult(Object success, SecureHash transactionId) { public FlowResult(Object success, SecureHash transactionId) {
this.successStatus = success; this.successStatus = success;
this.transactionId = transactionId.toString(); this.transactionId = transactionId;
this.failureStatus = null; this.failureStatus = null;
} }