Skip to content

Commit

Permalink
fix validation of 258 set tags
Browse files Browse the repository at this point in the history
  • Loading branch information
janmazak committed Dec 21, 2023
1 parent 59f4c2e commit 7748824
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 128 deletions.
2 changes: 2 additions & 0 deletions src/errors/validationError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export enum ValidationErrorReason {
REFERENCE_SCRIPT_MUST_NOT_BE_EMPTY_IF_DEFINED = 'Reference script must not be empty if defined',
COLLATERAL_RETURN_MUST_NOT_CONTAIN_DATUM = 'Collateral return must not contain datum',
COLLATERAL_RETURN_MUST_NOT_CONTAIN_REFERENCE_SCRIPT = 'Collateral return must not contain reference script',
TX_INCONSISTENT_SET_TAGS = 'Inconsistent set tags 258 across the transaction body',
}

const FIXABLE = true
Expand Down Expand Up @@ -97,6 +98,7 @@ const validationErrorFixability: Record<ValidationErrorReason, boolean> = {
[ValidationErrorReason.COLLATERAL_RETURN_MUST_NOT_CONTAIN_DATUM]: FIXABLE,
[ValidationErrorReason.COLLATERAL_RETURN_MUST_NOT_CONTAIN_REFERENCE_SCRIPT]:
FIXABLE,
[ValidationErrorReason.TX_INCONSISTENT_SET_TAGS]: FIXABLE,
}

export type ValidationError = {
Expand Down
61 changes: 47 additions & 14 deletions src/txTransformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import type {
FixLenBuffer,
Int,
Multiasset,
PoolRegistrationCertificate,
ReferenceScript,
Transaction,
TransactionBody,
TransactionOutput,
Uint,
Unparsed,
} from './types'
import {AmountType, DatumType, TxOutputFormat} from './types'
import {AmountType, CertificateType, DatumType, TxOutputFormat} from './types'
import {blake2b256, encodeToCbor, unreachable} from './utils'

const transformOptionalList = <T>(optionalList?: T[]): T[] | undefined =>
Expand Down Expand Up @@ -120,22 +121,54 @@ const transformAuxiliaryDataHash = (
? auxiliaryDataHash
: blake2b256(encodeToCbor(auxiliaryData))

// Add 258 tags everywhere if at least one is present.
// In the future, when the tags are mandatory,
// we should add them everywhere even if not present.
export const makeSetTagsConsistent = (
txBody: TransactionBody,
): TransactionBody => {
const poolRegistrationCertificate = txBody.certificates?.items.find(
({type}) => type === CertificateType.POOL_REGISTRATION,
) as PoolRegistrationCertificate
const allSets = [
txBody.inputs,
txBody.certificates,
txBody.collateralInputs,
txBody.requiredSigners,
txBody.referenceInputs,
txBody.proposalProcedures,
poolRegistrationCertificate?.poolParams.poolOwners,
]
const tagIsPresent = allSets.some((s) => s !== undefined && s.hasTag)
if (tagIsPresent) {
allSets.map((s) => {
if (s !== undefined) {
s.hasTag = true
}
})
}
return txBody
}

export const transformTxBody = (
txBody: TransactionBody,
auxiliaryData: Unparsed,
): TransactionBody => ({
...txBody,
outputs: txBody.outputs.map(transformTxOutput),
withdrawals: transformOptionalList(txBody.withdrawals),
auxiliaryDataHash: transformAuxiliaryDataHash(
txBody.auxiliaryDataHash,
auxiliaryData,
),
collateralReturnOutput:
txBody.collateralReturnOutput &&
transformTxOutput(txBody.collateralReturnOutput),
votingProcedures: transformOptionalList(txBody.votingProcedures),
})
): TransactionBody => {
const transformedBody = {
...txBody,
outputs: txBody.outputs.map(transformTxOutput),
withdrawals: transformOptionalList(txBody.withdrawals),
auxiliaryDataHash: transformAuxiliaryDataHash(
txBody.auxiliaryDataHash,
auxiliaryData,
),
collateralReturnOutput:
txBody.collateralReturnOutput &&
transformTxOutput(txBody.collateralReturnOutput),
votingProcedures: transformOptionalList(txBody.votingProcedures),
}
return makeSetTagsConsistent(transformedBody)
}

export const transformTx = (tx: Transaction): Transaction => ({
...tx,
Expand Down
22 changes: 22 additions & 0 deletions src/txValidators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
CddlNonEmptySet,
CddlNonEmptyOrderedSet,
VoterVotes,
PoolRegistrationCertificate,
} from './types'
import {AmountType, CertificateType, DatumType, TxOutputFormat} from './types'
import {bind, unreachable} from './utils'
Expand Down Expand Up @@ -630,6 +631,27 @@ function* validateTxBody(txBody: TransactionBody): ValidatorReturnType {

// extra checks for transactions containing stake pool registration certificates
yield* validatePoolRegistrationTransaction(txBody)

// check for consistency of set tags
const poolRegistrationCertificate = txBody.certificates?.items.find(
({type}) => type === CertificateType.POOL_REGISTRATION,
) as PoolRegistrationCertificate
const allSets = [
txBody.inputs,
txBody.certificates,
txBody.collateralInputs,
txBody.requiredSigners,
txBody.referenceInputs,
txBody.proposalProcedures,
poolRegistrationCertificate?.poolParams.poolOwners,
]
const tagIsPresent = allSets.some((s) => s !== undefined && s.hasTag)
const tagIsAbsent = allSets.some((s) => s !== undefined && !s.hasTag)
const tagsAreInconsistent = tagIsPresent && tagIsAbsent
yield* validate(
!tagsAreInconsistent,
err(ValidationErrorReason.TX_INCONSISTENT_SET_TAGS, 'transaction_body'),
)
}

/**
Expand Down
Loading

0 comments on commit 7748824

Please sign in to comment.