LinearId constraints

The implementation of LinearID constraints have a few more complexities.

LinearIDs are used when we want to represent a linear chain of evolving states on the ledger. There is an implicit assumption that to avoid branching of the linear chain there will be at most one primary input state and one primary output state.

Later the Path constraints will explicitly state that cannot be more than one primary input or primary output state. However, we should program defensively, so we add a pre-check that will throw a meaningful error if the transaction has more than one primary input or primary output state.

After the pre-check, we need to identify the situations where it is appropriate to check for matching LinearIds. This will be wherever there is both an primary input state and a primary output state and the Multiplicity is marked as ‘1: Matched’

From the diagram we can see that occurs for the Reject, Repropose and Agree commands:

Hence, we will perform a switch (when in Kotlin) on the commands and apply the linear ID check for those commands.

AgreementContract.kt:

    fun verifyLinearIDConstraints(tx: LedgerTransaction){

        val command = tx.commands.requireSingleCommand<AgreementContract.Commands>()
        val inputStates = tx.inputsOfType<AgreementState>()
        val outputStates = tx.outputsOfType<AgreementState>()

        // Assume that if using LinearID we want a maximum of one Primary input state and a maximum one Primary output state
        // This is a guard which shouldn't be triggered because the Path constraints should have already ensured there is
        // a maximum of one Primary input state and a maximum one Primary output state
        requireThat{
            "When using LinearStates there should be a maximum of one Primary input state." using (inputStates.size <= 1)
            "When using LinearStates there should be a maximum of one Primary output state." using (outputStates.size <= 1)
        }

        val inputState = inputStates.singleOrNull()
        val outputState = outputStates.singleOrNull()

        val commandName = command.value::class.java.simpleName
        when (command.value){
            is Commands.Reject,
            is Commands.Repropose,
            is Commands.Agree-> {
                requireThat {"When the Command is $commandName the LinearID must not change." using(inputState?.linearId == outputState?.linearId)}
            }
        }
    }

Was this page helpful?

Thanks for your feedback!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.

We're sorry this page wasn't helpful. Let us know how we can make it better!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Create an issue

Create a new GitHub issue in this repository - submit technical feedback, draw attention to a potential documentation bug, or share ideas for improvement and general feedback.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.