* Minor formatting changes. (#3758)

* NotaryServiceFlow now takes references into account when comparing number of inputs vs maxAllowedInputs.
* Added reference state support for BFTSMaRt notary.

* Fixes broken BFT notary tests.
This commit is contained in:
Roger Willis
2018-08-10 08:51:56 +01:00
committed by GitHub
parent ce5f38104b
commit b0d36b6617
6 changed files with 39 additions and 12 deletions

View File

@ -20,7 +20,7 @@ import net.corda.core.utilities.unwrap
abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service: TrustedAuthorityNotaryService) : FlowLogic<Void?>() { abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service: TrustedAuthorityNotaryService) : FlowLogic<Void?>() {
companion object { companion object {
// TODO: Determine an appropriate limit and also enforce in the network parameters and the transaction builder. // TODO: Determine an appropriate limit and also enforce in the network parameters and the transaction builder.
private const val maxAllowedInputs = 10_000 private const val maxAllowedInputsAndReferences = 10_000
} }
@Suspendable @Suspendable
@ -44,9 +44,10 @@ abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service:
/** Checks whether the number of input states is too large. */ /** Checks whether the number of input states is too large. */
protected fun checkInputs(inputs: List<StateRef>) { protected fun checkInputs(inputs: List<StateRef>) {
if (inputs.size > maxAllowedInputs) { if (inputs.size > maxAllowedInputsAndReferences) {
val error = NotaryError.TransactionInvalid( val error = NotaryError.TransactionInvalid(
IllegalArgumentException("A transaction cannot have more than $maxAllowedInputs inputs, received: ${inputs.size}") IllegalArgumentException("A transaction cannot have more than $maxAllowedInputsAndReferences " +
"inputs or references, received: ${inputs.size}")
) )
throw NotaryInternalException(error) throw NotaryInternalException(error)
} }

View File

@ -26,7 +26,14 @@ abstract class TrustedAuthorityNotaryService : NotaryService() {
* this method does not throw an exception when input states are present multiple times within the transaction. * this method does not throw an exception when input states are present multiple times within the transaction.
*/ */
@JvmOverloads @JvmOverloads
fun commitInputStates(inputs: List<StateRef>, txId: SecureHash, caller: Party, requestSignature: NotarisationRequestSignature, timeWindow: TimeWindow?, references: List<StateRef> = emptyList()) { fun commitInputStates(
inputs: List<StateRef>,
txId: SecureHash,
caller: Party,
requestSignature: NotarisationRequestSignature,
timeWindow: TimeWindow?,
references: List<StateRef> = emptyList()
) {
try { try {
uniquenessProvider.commit(inputs, txId, caller, requestSignature, timeWindow, references) uniquenessProvider.commit(inputs, txId, caller, requestSignature, timeWindow, references)
} catch (e: NotaryInternalException) { } catch (e: NotaryInternalException) {

View File

@ -139,10 +139,11 @@ class BFTNonValidatingNotaryService(
return try { return try {
val id = transaction.id val id = transaction.id
val inputs = transaction.inputs val inputs = transaction.inputs
val references = transaction.references
val notary = transaction.notary val notary = transaction.notary
val timeWindow = (transaction as? FilteredTransaction)?.timeWindow val timeWindow = (transaction as? FilteredTransaction)?.timeWindow
if (notary !in services.myInfo.legalIdentities) throw NotaryInternalException(NotaryError.WrongNotary) if (notary !in services.myInfo.legalIdentities) throw NotaryInternalException(NotaryError.WrongNotary)
commitInputStates(inputs, id, callerIdentity.name, requestSignature, timeWindow) commitInputStates(inputs, id, callerIdentity.name, requestSignature, timeWindow, references)
log.debug { "Inputs committed successfully, signing $id" } log.debug { "Inputs committed successfully, signing $id" }
BFTSMaRt.ReplicaResponse.Signature(sign(id)) BFTSMaRt.ReplicaResponse.Signature(sign(id))
} catch (e: NotaryInternalException) { } catch (e: NotaryInternalException) {

View File

@ -223,17 +223,35 @@ object BFTSMaRt {
*/ */
abstract fun executeCommand(command: ByteArray): ByteArray? abstract fun executeCommand(command: ByteArray): ByteArray?
protected fun commitInputStates(states: List<StateRef>, txId: SecureHash, callerName: CordaX500Name, requestSignature: NotarisationRequestSignature, timeWindow: TimeWindow?) { private fun checkConflict(
conflictingStates: LinkedHashMap<StateRef, StateConsumptionDetails>,
states: List<StateRef>,
type: StateConsumptionDetails.ConsumedStateType
) {
states.forEach { stateRef ->
commitLog[stateRef]?.let { conflictingStates[stateRef] = StateConsumptionDetails(it.sha256(), type) }
}
}
protected fun commitInputStates(
states: List<StateRef>,
txId: SecureHash,
callerName: CordaX500Name,
requestSignature: NotarisationRequestSignature,
timeWindow: TimeWindow?,
references: List<StateRef> = emptyList()
) {
log.debug { "Attempting to commit inputs for transaction: $txId" } log.debug { "Attempting to commit inputs for transaction: $txId" }
services.database.transaction { services.database.transaction {
logRequest(txId, callerName, requestSignature) logRequest(txId, callerName, requestSignature)
val conflictingStates = LinkedHashMap<StateRef, StateConsumptionDetails>() val conflictingStates = LinkedHashMap<StateRef, StateConsumptionDetails>()
for (state in states) {
commitLog[state]?.let { conflictingStates[state] = StateConsumptionDetails(it.sha256()) } checkConflict(conflictingStates, states, StateConsumptionDetails.ConsumedStateType.INPUT_STATE)
} checkConflict(conflictingStates, references, StateConsumptionDetails.ConsumedStateType.REFERENCE_INPUT_STATE)
if (conflictingStates.isNotEmpty()) { if (conflictingStates.isNotEmpty()) {
if (!isConsumedByTheSameTx(txId.sha256(), conflictingStates)) { if (!isConsumedByTheSameTx(txId.sha256(), conflictingStates)) {
log.debug { "Failure, input states already committed: ${conflictingStates.keys}" } log.debug { "Failure, input states or references already committed: ${conflictingStates.keys}" }
throw NotaryInternalException(NotaryError.Conflict(txId, conflictingStates)) throw NotaryInternalException(NotaryError.Conflict(txId, conflictingStates))
} }
} else { } else {

View File

@ -24,7 +24,7 @@ class NonValidatingNotaryFlow(otherSideSession: FlowSession, service: TrustedAut
@Suspendable @Suspendable
override fun validateRequest(requestPayload: NotarisationPayload): TransactionParts { override fun validateRequest(requestPayload: NotarisationPayload): TransactionParts {
val transaction = requestPayload.coreTransaction val transaction = requestPayload.coreTransaction
checkInputs(transaction.inputs) checkInputs(transaction.inputs + transaction.references)
val request = NotarisationRequest(transaction.inputs, transaction.id) val request = NotarisationRequest(transaction.inputs, transaction.id)
validateRequestSignature(request, requestPayload.requestSignature) validateRequestSignature(request, requestPayload.requestSignature)
val parts = extractParts(transaction) val parts = extractParts(transaction)

View File

@ -31,7 +31,7 @@ class ValidatingNotaryFlow(otherSideSession: FlowSession, service: TrustedAuthor
override fun validateRequest(requestPayload: NotarisationPayload): TransactionParts { override fun validateRequest(requestPayload: NotarisationPayload): TransactionParts {
try { try {
val stx = requestPayload.signedTransaction val stx = requestPayload.signedTransaction
checkInputs(stx.inputs) checkInputs(stx.inputs + stx.references)
validateRequestSignature(NotarisationRequest(stx.inputs, stx.id), requestPayload.requestSignature) validateRequestSignature(NotarisationRequest(stx.inputs, stx.id), requestPayload.requestSignature)
val notary = stx.notary val notary = stx.notary
checkNotary(notary) checkNotary(notary)