-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixed pathing error with kotlin customStateJSONandQuery app.
- Loading branch information
Showing
15 changed files
with
1,276 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
...otlin/com/r3/developers/cordapptemplate/customStateJSONandQuery/contracts/ChatContract.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package com.r3.developers.cordapptemplate.customStateJSONandQuery.contracts | ||
|
||
import com.r3.developers.cordapptemplate.customStateJSONandQuery.states.ChatState | ||
import net.corda.v5.base.exceptions.CordaRuntimeException | ||
import net.corda.v5.ledger.utxo.Command | ||
import net.corda.v5.ledger.utxo.Contract | ||
import net.corda.v5.ledger.utxo.transaction.UtxoLedgerTransaction | ||
|
||
class ChatContract: Contract { | ||
|
||
// Use an internal scoped constant to hold the error messages | ||
// This allows the tests to use them, meaning if they are updated you won't need to fix tests just because the wording was updated | ||
internal companion object { | ||
|
||
const val REQUIRE_SINGLE_COMMAND = "Requires a single command." | ||
const val UNKNOWN_COMMAND = "Command not allowed." | ||
const val OUTPUT_STATE_SHOULD_ONLY_HAVE_TWO_PARTICIPANTS = "The output state should have two and only two participants." | ||
const val TRANSACTION_SHOULD_BE_SIGNED_BY_ALL_PARTICIPANTS = "The transaction should have been signed by both participants." | ||
|
||
const val CREATE_COMMAND_SHOULD_HAVE_NO_INPUT_STATES = "When command is Create there should be no input states." | ||
const val CREATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE = "When command is Create there should be one and only one output state." | ||
|
||
const val UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_INPUT_STATE = "When command is Update there should be one and only one input state." | ||
const val UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE = "When command is Update there should be one and only one output state." | ||
const val UPDATE_COMMAND_ID_SHOULD_NOT_CHANGE = "When command is Update id must not change." | ||
const val UPDATE_COMMAND_CHATNAME_SHOULD_NOT_CHANGE = "When command is Update chatName must not change." | ||
const val UPDATE_COMMAND_PARTICIPANTS_SHOULD_NOT_CHANGE = "When command is Update participants must not change." | ||
} | ||
|
||
// Command Class used to indicate that the transaction should start a new chat. | ||
class Create: Command | ||
// Command Class used to indicate that the transaction should append a new ChatState to an existing chat. | ||
class Update: Command | ||
|
||
// verify() function is used to apply contract rules to the transaction. | ||
override fun verify(transaction: UtxoLedgerTransaction) { | ||
|
||
// Ensures that there is only one command in the transaction | ||
val command = transaction.commands.singleOrNull() ?: throw CordaRuntimeException(REQUIRE_SINGLE_COMMAND) | ||
|
||
// Applies a universal constraint (applies to all transactions irrespective of command) | ||
OUTPUT_STATE_SHOULD_ONLY_HAVE_TWO_PARTICIPANTS using { | ||
val output = transaction.outputContractStates.first() as ChatState | ||
output.participants.size== 2 | ||
} | ||
|
||
TRANSACTION_SHOULD_BE_SIGNED_BY_ALL_PARTICIPANTS using { | ||
val output = transaction.outputContractStates.first() as ChatState | ||
transaction.signatories.containsAll(output.participants) | ||
} | ||
|
||
// Switches case based on the command | ||
when(command) { | ||
// Rules applied only to transactions with the Create Command. | ||
is Create -> { | ||
CREATE_COMMAND_SHOULD_HAVE_NO_INPUT_STATES using (transaction.inputContractStates.isEmpty()) | ||
CREATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE using (transaction.outputContractStates.size == 1) | ||
} | ||
// Rules applied only to transactions with the Update Command. | ||
is Update -> { | ||
UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_INPUT_STATE using (transaction.inputContractStates.size == 1) | ||
UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE using (transaction.outputContractStates.size == 1) | ||
|
||
val input = transaction.inputContractStates.single() as ChatState | ||
val output = transaction.outputContractStates.single() as ChatState | ||
UPDATE_COMMAND_ID_SHOULD_NOT_CHANGE using (input.id == output.id) | ||
UPDATE_COMMAND_CHATNAME_SHOULD_NOT_CHANGE using (input.chatName == output.chatName) | ||
UPDATE_COMMAND_PARTICIPANTS_SHOULD_NOT_CHANGE using ( | ||
input.participants.toSet().intersect(output.participants.toSet()).size == 2) | ||
} | ||
else -> { | ||
throw CordaRuntimeException(UNKNOWN_COMMAND) | ||
} | ||
} | ||
} | ||
|
||
// Helper function to allow writing constraints in the Corda 4 '"text" using (boolean)' style | ||
private infix fun String.using(expr: Boolean) { | ||
if (!expr) throw CordaRuntimeException("Failed requirement: $this") | ||
} | ||
|
||
// Helper function to allow writing constraints in '"text" using {lambda}' style where the last expression | ||
// in the lambda is a boolean. | ||
private infix fun String.using(expr: () -> Boolean) { | ||
if (!expr.invoke()) throw CordaRuntimeException("Failed requirement: $this") | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
...otlin/com/r3/developers/cordapptemplate/customStateJSONandQuery/states/ChatJsonFactory.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.r3.developers.cordapptemplate.customStateJSONandQuery.states | ||
|
||
import net.corda.v5.application.marshalling.JsonMarshallingService | ||
import net.corda.v5.ledger.utxo.query.json.ContractStateVaultJsonFactory | ||
|
||
// This class represents a custom JSON factory for serializing/deserializing ChatState objects to JSON format after each use. | ||
class ChatJsonFactory : ContractStateVaultJsonFactory<ChatState> { | ||
|
||
// This function specifies the type of state this factory is responsible for. | ||
override fun getStateType(): Class<ChatState> = ChatState::class.java | ||
|
||
// Companion object containing constants used for JSON key names. | ||
companion object { | ||
const val ID = "Id" | ||
const val CHATNAME = "chatName" | ||
const val MESSAGE = "messageContent" | ||
const val MESSAGEFROM = "messageContentFrom" | ||
} | ||
|
||
// This function creates a JSON representation of a ChatState object. | ||
override fun create(state: ChatState, jsonMarshallingService: JsonMarshallingService): String { | ||
|
||
// Constructs a map representing the ChatState object using the provided constants. | ||
val jsonMap = mapOf( | ||
Pair(ID, state.id), | ||
Pair(CHATNAME, state.chatName), | ||
Pair(MESSAGE, state.message), | ||
Pair(MESSAGEFROM, state.messageFrom) | ||
) | ||
|
||
// Uses the JsonMarshallingService's format() function to serialize the map to JSON. | ||
return jsonMarshallingService.format(jsonMap) | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...main/kotlin/com/r3/developers/cordapptemplate/customStateJSONandQuery/states/ChatState.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.r3.developers.cordapptemplate.customStateJSONandQuery.states | ||
|
||
import com.r3.developers.cordapptemplate.customStateJSONandQuery.contracts.ChatContract | ||
import net.corda.v5.base.types.MemberX500Name | ||
import net.corda.v5.ledger.utxo.BelongsToContract | ||
import net.corda.v5.ledger.utxo.ContractState | ||
import java.security.PublicKey | ||
import java.util.* | ||
|
||
|
||
// The ChatState represents data stored on ledger. A chat consists of a linear series of messages between two | ||
// participants and is represented by a UUID. Any given pair of participants can have multiple chats | ||
// Each ChatState stores one message between the two participants in the chat. The backchain of ChatStates | ||
// represents the history of the chat. | ||
|
||
@BelongsToContract(ChatContract::class) | ||
data class ChatState( | ||
// Unique identifier for the chat. | ||
val id : UUID = UUID.randomUUID(), | ||
// Non-unique name for the chat. | ||
val chatName: String, | ||
// The MemberX500Name of the participant who sent the message. | ||
val messageFrom: MemberX500Name, | ||
// The message | ||
val message: String, | ||
// The participants to the chat, represented by their public key. | ||
private val participants: List<PublicKey>) : ContractState { | ||
|
||
override fun getParticipants(): List<PublicKey> { | ||
return participants | ||
} | ||
|
||
// Helper function to create a new ChatState from the previous (input) ChatState. | ||
fun updateMessage(messageFrom: MemberX500Name, message: String) = | ||
copy(messageFrom = messageFrom, message = message) | ||
} | ||
|
20 changes: 20 additions & 0 deletions
20
...otlin/com/r3/developers/cordapptemplate/customStateJSONandQuery/states/CustomChatQuery.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.r3.developers.cordapptemplate.customStateJSONandQuery.states | ||
|
||
import net.corda.v5.ledger.utxo.query.VaultNamedQueryFactory | ||
import net.corda.v5.ledger.utxo.query.registration.VaultNamedQueryBuilderFactory | ||
|
||
class ChatCustomQueryFactory : VaultNamedQueryFactory { | ||
override fun create(vaultNamedQueryBuilderFactory: VaultNamedQueryBuilderFactory) { | ||
vaultNamedQueryBuilderFactory.create("GET_ALL_MSG") | ||
.whereJson( | ||
"WHERE visible_states.custom_representation ? 'com.r3.developers.cordapptemplate.customStateJSONandQuery.states.ChatState' " | ||
) | ||
.register() | ||
|
||
vaultNamedQueryBuilderFactory.create("GET_MSG_FROM") | ||
.whereJson( | ||
"WHERE visible_states.custom_representation -> 'com.r3.developers.cordapptemplate.customStateJSONandQuery.states.ChatState' ->> 'messageContentFrom' = :nameOfSender" | ||
) | ||
.register() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.