@xyo-network/chain-validation 1.5.30 → 1.5.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/neutral/index.mjs +126 -76
  2. package/dist/neutral/index.mjs.map +1 -1
  3. package/dist/types/block/validateBlock.d.ts.map +1 -1
  4. package/dist/types/block/validators/AllowedPayloadSchemas.d.ts.map +1 -1
  5. package/dist/types/block/validators/Fields.d.ts +1 -1
  6. package/dist/types/block/validators/Fields.d.ts.map +1 -1
  7. package/dist/types/block/validators/JsonSchema.d.ts +1 -1
  8. package/dist/types/block/validators/JsonSchema.d.ts.map +1 -1
  9. package/dist/types/block/validators/PreviousHash.d.ts.map +1 -1
  10. package/dist/types/boundwitness/validators/BoundWitnessReferences.d.ts.map +1 -1
  11. package/dist/types/boundwitness/validators/BoundWitnessSignatures.d.ts.map +1 -1
  12. package/dist/types/elevatedPayload/payloads/validateSchemaInBlock.d.ts.map +1 -1
  13. package/dist/types/elevatedPayload/payloads/validateTransferInBlock.d.ts +1 -1
  14. package/dist/types/elevatedPayload/payloads/validateTransferInBlock.d.ts.map +1 -1
  15. package/dist/types/elevatedPayload/validatePayloadInBlock.d.ts.map +1 -1
  16. package/dist/types/hydratedBlock/validateHydratedBlock.d.ts +2 -2
  17. package/dist/types/hydratedBlock/validateHydratedBlock.d.ts.map +1 -1
  18. package/dist/types/hydratedBlock/validators/Payloads.d.ts +2 -2
  19. package/dist/types/hydratedBlock/validators/Payloads.d.ts.map +1 -1
  20. package/dist/types/hydratedBlockState/validateHydratedBlockState.d.ts.map +1 -1
  21. package/dist/types/hydratedBlockState/validators/RequiredBalance.d.ts.map +1 -1
  22. package/dist/types/transaction/validateTransaction.d.ts +2 -2
  23. package/dist/types/transaction/validateTransaction.d.ts.map +1 -1
  24. package/dist/types/transaction/validators/TransactionDurationValidator.d.ts +2 -2
  25. package/dist/types/transaction/validators/TransactionDurationValidator.d.ts.map +1 -1
  26. package/dist/types/transaction/validators/TransactionElevationValidator.d.ts +2 -2
  27. package/dist/types/transaction/validators/TransactionElevationValidator.d.ts.map +1 -1
  28. package/dist/types/transaction/validators/TransactionFromValidator.d.ts +2 -2
  29. package/dist/types/transaction/validators/TransactionFromValidator.d.ts.map +1 -1
  30. package/dist/types/transaction/validators/TransactionGasValidator.d.ts +2 -2
  31. package/dist/types/transaction/validators/TransactionGasValidator.d.ts.map +1 -1
  32. package/dist/types/transaction/validators/TransactionJsonSchemaValidator.d.ts +2 -2
  33. package/dist/types/transaction/validators/TransactionJsonSchemaValidator.d.ts.map +1 -1
  34. package/dist/types/transaction/validators/TransactionProtocolValidator.d.ts +2 -2
  35. package/dist/types/transaction/validators/TransactionProtocolValidator.d.ts.map +1 -1
  36. package/package.json +6 -6
  37. package/src/block/validateBlock.ts +3 -2
  38. package/src/block/validators/AllowedPayloadSchemas.ts +4 -4
  39. package/src/block/validators/Fields.ts +7 -5
  40. package/src/block/validators/JsonSchema.ts +7 -6
  41. package/src/block/validators/PreviousHash.ts +6 -5
  42. package/src/boundwitness/validators/BoundWitnessReferences.ts +9 -8
  43. package/src/boundwitness/validators/BoundWitnessSignatures.ts +5 -4
  44. package/src/elevatedPayload/payloads/validateChainStakeIntentInBlock.ts +4 -4
  45. package/src/elevatedPayload/payloads/validateHashInBlock.ts +4 -4
  46. package/src/elevatedPayload/payloads/validateSchemaInBlock.ts +3 -2
  47. package/src/elevatedPayload/payloads/validateTransferInBlock.ts +6 -4
  48. package/src/elevatedPayload/validatePayloadInBlock.ts +6 -5
  49. package/src/hydratedBlock/validateHydratedBlock.ts +7 -6
  50. package/src/hydratedBlock/validators/Payloads.ts +7 -6
  51. package/src/hydratedBlockState/validateHydratedBlockState.ts +7 -2
  52. package/src/hydratedBlockState/validators/RequiredBalance.ts +13 -4
  53. package/src/transaction/validateTransaction.ts +5 -5
  54. package/src/transaction/validators/TransactionDurationValidator.ts +12 -11
  55. package/src/transaction/validators/TransactionElevationValidator.ts +8 -8
  56. package/src/transaction/validators/TransactionFromValidator.ts +10 -9
  57. package/src/transaction/validators/TransactionGasValidator.ts +42 -18
  58. package/src/transaction/validators/TransactionJsonSchemaValidator.ts +9 -9
  59. package/src/transaction/validators/TransactionProtocolValidator.ts +9 -8
@@ -1,19 +1,19 @@
1
1
  import {
2
- type BlockBoundWitness, type BlockValidatorFunction, isAllowedBlockPayloadSchema,
2
+ type BlockBoundWitness, BlockValidationError, type BlockValidatorFunction, isAllowedBlockPayloadSchema,
3
3
  } from '@xyo-network/xl1-protocol'
4
4
 
5
5
  export const BlockAllowedPayloadSchemasValidator: BlockValidatorFunction = (
6
6
  block: BlockBoundWitness,
7
7
  ) => {
8
- const errors: Error[] = []
8
+ const errors: (BlockValidationError | Error)[] = []
9
9
  try {
10
10
  for (const schema of block.payload_schemas) {
11
11
  if (!isAllowedBlockPayloadSchema(schema)) {
12
- errors.push(new Error(`payload schema not allowed in block: ${schema}`))
12
+ errors.push(new BlockValidationError(block, `payload schema not allowed in block: ${schema}`))
13
13
  }
14
14
  }
15
15
  } catch (e) {
16
- errors.push(new Error(`Failed BlockAllowedPayloadSchemasValidator: ${e instanceof Error ? e.message : String(e)}`))
16
+ errors.push(new BlockValidationError(block, `Failed BlockAllowedPayloadSchemasValidator: ${e instanceof Error ? e.message : String(e)}`))
17
17
  }
18
18
  return errors
19
19
  }
@@ -1,16 +1,18 @@
1
1
  import type { Address, Hash } from '@xylabs/hex'
2
2
  import { isDefined } from '@xylabs/typeof'
3
3
  import { BoundWitnessSchema } from '@xyo-network/boundwitness-model'
4
- import type { BlockBoundWitness, BlockValidatorFunction } from '@xyo-network/xl1-protocol'
4
+ import {
5
+ type BlockBoundWitness, BlockValidationError, type BlockValidatorFunction,
6
+ } from '@xyo-network/xl1-protocol'
5
7
 
6
8
  export const BlockFieldsValidator: BlockValidatorFunction = (
7
9
  block: BlockBoundWitness,
8
10
  chainId?: Address,
9
11
  ) => {
10
- const errors: Error[] = []
12
+ const errors: (BlockValidationError | Error)[] = []
11
13
  try {
12
14
  if (isDefined(chainId) && block.chain !== chainId.toLowerCase()) {
13
- errors.push(new Error('Invalid chain id'))
15
+ errors.push(new BlockValidationError(block, 'Invalid chain id'))
14
16
  }
15
17
 
16
18
  // get transaction hashes
@@ -23,10 +25,10 @@ export const BlockFieldsValidator: BlockValidatorFunction = (
23
25
 
24
26
  // check if transaction hashes are unique
25
27
  if (new Set(txHashes).size < txHashes.length) {
26
- errors.push(new Error(`Duplicate Transaction Hashes: ${txHashes}`))
28
+ errors.push(new BlockValidationError(block, `Duplicate Transaction Hashes: ${txHashes}`))
27
29
  }
28
30
  } catch (e) {
29
- errors.push(new Error(`Failed BlockFieldsValidator: ${e instanceof Error ? e.message : String(e)}`))
31
+ errors.push(new BlockValidationError(block, `Failed BlockFieldsValidator: ${e instanceof Error ? e.message : String(e)}`))
30
32
  }
31
33
  return errors
32
34
  }
@@ -1,24 +1,25 @@
1
1
  import { BlockBoundWitnessWithStorageMetaJsonSchema } from '@xyo-network/chain-schema'
2
- import type { BlockBoundWitness, BlockValidatorFunction } from '@xyo-network/xl1-protocol'
2
+ import {
3
+ type BlockBoundWitness, BlockValidationError, type BlockValidatorFunction,
4
+ } from '@xyo-network/xl1-protocol'
3
5
  import type { AnySchema } from 'ajv'
4
6
  import { Ajv } from 'ajv'
5
7
 
6
8
  export const BlockJsonSchemaValidator = (jsonSchema: AnySchema = BlockBoundWitnessWithStorageMetaJsonSchema): BlockValidatorFunction => async (
7
9
  block: BlockBoundWitness,
8
10
  ) => {
9
- const errors: Error[] = []
11
+ const errors: (BlockValidationError | Error)[] = []
10
12
  try {
11
13
  const ajv = new Ajv({ allErrors: true, strict: true })
12
14
  // see if you can export the super set
13
15
  const validate = ajv.compile(jsonSchema)
14
16
  await validate(block)
15
17
  if ((validate.errors ?? []).length > 0) {
16
- const error = new Error('failed JSON schema validation')
17
- error.cause = validate.errors
18
- errors.push(error)
18
+ const error = new BlockValidationError(block, 'failed JSON schema validation: ')
19
+ errors.push(error, ...validate.errors?.map(e => new Error(` ${e.instancePath} ${e.message ?? ''}`)) ?? [])
19
20
  }
20
21
  } catch (e) {
21
- errors.push(new Error(`Failed BlockJsonSchemaValidator: ${e instanceof Error ? e.message : String(e)}`))
22
+ errors.push(new BlockValidationError(block, `Failed BlockJsonSchemaValidator: ${e instanceof Error ? e.message : String(e)}`))
22
23
  }
23
24
  return errors
24
25
  }
@@ -1,28 +1,29 @@
1
1
  import { isHash } from '@xylabs/hex'
2
2
  import type { BlockBoundWitness, BlockValidatorFunction } from '@xyo-network/xl1-protocol'
3
+ import { BlockValidationError } from '@xyo-network/xl1-protocol'
3
4
 
4
5
  export const BlockPreviousHashValidator: BlockValidatorFunction = (
5
6
  block: BlockBoundWitness,
6
7
  ) => {
7
- const errors: Error[] = []
8
+ const errors: (BlockValidationError | Error)[] = []
8
9
  try {
9
10
  const blockNumber = block.block
10
11
  if (blockNumber > 0n) {
11
12
  // if this is not the first block, validate previous hashes
12
13
  if (!isHash(block.previous)) {
13
- errors.push(new Error('previous hash is missing or invalid'))
14
+ errors.push(new BlockValidationError(block, 'previous hash is missing or invalid'))
14
15
  }
15
16
  } else if (blockNumber === 0) {
16
17
  // if this is the first block, validate previous hashes
17
18
  if (block.previous !== null) {
18
- errors.push(new Error('previous hash should not be set'))
19
+ errors.push(new BlockValidationError(block, 'previous hash should not be set'))
19
20
  }
20
21
  } else {
21
22
  // we have a negative block number
22
- errors.push(new Error('invalid block number'))
23
+ errors.push(new BlockValidationError(block, 'invalid block number'))
23
24
  }
24
25
  } catch (e) {
25
- errors.push(new Error(`Failed BlockPreviousHashValidator: ${e instanceof Error ? e.message : String(e)}`))
26
+ errors.push(new BlockValidationError(block, `Failed BlockPreviousHashValidator: ${e instanceof Error ? e.message : String(e)}`))
26
27
  }
27
28
  return errors
28
29
  }
@@ -8,6 +8,7 @@ import type {
8
8
  } from '@xyo-network/payload-model'
9
9
  import { isAnyPayload } from '@xyo-network/payload-model'
10
10
  import type { HydratedBoundWitnessValidationFunction, HydratedBoundWitnessWithHashStorageMeta } from '@xyo-network/xl1-protocol'
11
+ import { HydratedBoundWitnessValidationError } from '@xyo-network/xl1-protocol'
11
12
 
12
13
  function getPayloadsFromPayloadArray(payloads: WithHashStorageMeta<Payload>[], hashes: Hash[]): (WithHashStorageMeta<Payload> | undefined)[] {
13
14
  return hashes.map(hash => payloads.find(payload => payload._hash === hash || payload._dataHash === hash))
@@ -16,12 +17,12 @@ function getPayloadsFromPayloadArray(payloads: WithHashStorageMeta<Payload>[], h
16
17
  export const BoundWitnessReferencesValidator
17
18
  = <T extends BoundWitness = BoundWitness>(allowedSchemas?: Schema[]): HydratedBoundWitnessValidationFunction<T> => (
18
19
  [bw, payloadSet]: HydratedBoundWitnessWithHashStorageMeta<T>,
19
- ): Promisable<Error[]> => {
20
- const errors: Error[] = []
20
+ ): Promisable<(HydratedBoundWitnessValidationError | Error)[]> => {
21
+ const errors: (HydratedBoundWitnessValidationError | Error)[] = []
21
22
  try {
22
23
  const payloads = getPayloadsFromPayloadArray(payloadSet, bw.payload_hashes)
23
24
  if (payloads.length !== bw.payload_hashes.length) {
24
- errors.push(new Error('unable to locate payloads'))
25
+ errors.push(new HydratedBoundWitnessValidationError([bw, payloadSet], 'unable to locate payloads'))
25
26
  }
26
27
 
27
28
  // check if payloads are valid and if their schemas match the declared schemas
@@ -31,23 +32,23 @@ export const BoundWitnessReferencesValidator
31
32
  const payloadDataHashIndex = bw.payload_hashes.indexOf(payload._dataHash)
32
33
  const payloadIndex = Math.max(payloadHashIndex, payloadDataHashIndex)
33
34
  if (payloadIndex === -1) {
34
- errors.push(new Error('payload hash not found'))
35
+ errors.push(new HydratedBoundWitnessValidationError([bw, payloadSet], 'payload hash not found'))
35
36
  }
36
37
 
37
38
  const declaredSchema = bw.payload_schemas[payloadIndex]
38
39
  if (declaredSchema !== payload.schema) {
39
- errors.push(new Error('mismatched schema'))
40
+ errors.push(new HydratedBoundWitnessValidationError([bw, payloadSet], 'mismatched schema'))
40
41
  }
41
42
 
42
43
  if (allowedSchemas && !allowedSchemas.includes(payload.schema)) {
43
- errors.push(new Error(`disallowed schema [${payload.schema}]`))
44
+ errors.push(new HydratedBoundWitnessValidationError([bw, payloadSet], `disallowed schema [${payload.schema}]`))
44
45
  }
45
46
  } else {
46
- errors.push(new Error('invalid payload'))
47
+ errors.push(new HydratedBoundWitnessValidationError([bw, payloadSet], 'invalid payload'))
47
48
  }
48
49
  }
49
50
  } catch (ex) {
50
- errors.push(new Error('validation excepted'), ex as Error)
51
+ errors.push(new HydratedBoundWitnessValidationError([bw, payloadSet], 'validation excepted'), ex as Error)
51
52
  }
52
53
  return errors
53
54
  }
@@ -4,21 +4,22 @@ import { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
4
4
  import type { BoundWitness } from '@xyo-network/boundwitness-model'
5
5
  import { BoundWitnessValidator } from '@xyo-network/boundwitness-validator'
6
6
  import type { BoundWitnessValidationFunction } from '@xyo-network/xl1-protocol'
7
+ import { BoundWitnessValidationError } from '@xyo-network/xl1-protocol'
7
8
 
8
9
  export const BoundWitnessSignaturesValidator: BoundWitnessValidationFunction = async (
9
10
  bw: BoundWitness,
10
- ): Promise<Error[]> => {
11
- const errors: Error[] = []
11
+ ) => {
12
+ const errors: (BoundWitnessValidationError | Error)[] = []
12
13
  try {
13
14
  const dataHash = await BoundWitnessBuilder.dataHash(bw)
14
- const results: [Address, Error[]][] = await Promise.all(bw.addresses.map(async (address, index) => {
15
+ const results: [Address, (Error | BoundWitnessValidationError)[]][] = await Promise.all(bw.addresses.map(async (address, index) => {
15
16
  return [address, await BoundWitnessValidator.validateSignature(toArrayBuffer(dataHash), toArrayBuffer(address), toArrayBuffer(bw.$signatures[index]))]
16
17
  }))
17
18
  for (const [, bwErrors] of results) {
18
19
  errors.push(...bwErrors)
19
20
  }
20
21
  } catch (ex) {
21
- errors.push(new Error('validation excepted'), ex as Error)
22
+ errors.push(new BoundWitnessValidationError(bw, 'validation excepted'), ex as Error)
22
23
  }
23
24
  return errors
24
25
  }
@@ -1,17 +1,17 @@
1
1
  import type { HydratedBlock, InBlockPayloadValidationFunction } from '@xyo-network/xl1-protocol'
2
- import { isChainStakeIntent } from '@xyo-network/xl1-protocol'
2
+ import { InBlockPayloadValidationError, isChainStakeIntent } from '@xyo-network/xl1-protocol'
3
3
 
4
4
  import { validateTypedPayloadInBlock } from '../lib/index.ts'
5
5
 
6
6
  export const validateChainStakeIntentInBlock: InBlockPayloadValidationFunction = async (
7
7
  payload,
8
8
  block: HydratedBlock,
9
- ): Promise<Error[]> => {
10
- const errors: Error[] = []
9
+ ): Promise<(InBlockPayloadValidationError | Error)[]> => {
10
+ const errors: (InBlockPayloadValidationError | Error)[] = []
11
11
  try {
12
12
  errors.push(...await validateTypedPayloadInBlock(payload, block, isChainStakeIntent))
13
13
  } catch (e) {
14
- errors.push(new Error(`Failed validateChainStakeIntentInBlock: ${e instanceof Error ? e.message : String(e)}`))
14
+ errors.push(new InBlockPayloadValidationError(block, payload, `Failed validateChainStakeIntentInBlock: ${e instanceof Error ? e.message : String(e)}`))
15
15
  }
16
16
  return errors
17
17
  }
@@ -1,17 +1,17 @@
1
1
  import type { HydratedBlock, InBlockPayloadValidationFunction } from '@xyo-network/xl1-protocol'
2
- import { isHashPayload } from '@xyo-network/xl1-protocol'
2
+ import { InBlockPayloadValidationError, isHashPayload } from '@xyo-network/xl1-protocol'
3
3
 
4
4
  import { validateTypedPayloadInBlock } from '../lib/index.ts'
5
5
 
6
6
  export const validateHashInBlock: InBlockPayloadValidationFunction = async (
7
7
  payload,
8
8
  block: HydratedBlock,
9
- ): Promise<Error[]> => {
10
- const errors: Error[] = []
9
+ ): Promise<(InBlockPayloadValidationError | Error)[]> => {
10
+ const errors: (InBlockPayloadValidationError | Error)[] = []
11
11
  try {
12
12
  errors.push(...await validateTypedPayloadInBlock(payload, block, isHashPayload))
13
13
  } catch (e) {
14
- errors.push(new Error(`Failed validateHashInBlock: ${e instanceof Error ? e.message : String(e)}`))
14
+ errors.push(new InBlockPayloadValidationError(block, payload, `Failed validateHashInBlock: ${e instanceof Error ? e.message : String(e)}`))
15
15
  }
16
16
  return errors
17
17
  }
@@ -1,17 +1,18 @@
1
1
  import { isSchemaPayload } from '@xyo-network/schema-payload-plugin'
2
2
  import type { HydratedBlock, InBlockPayloadValidationFunction } from '@xyo-network/xl1-protocol'
3
+ import { InBlockPayloadValidationError } from '@xyo-network/xl1-protocol'
3
4
 
4
5
  import { validateTypedPayloadInBlock } from '../lib/index.ts'
5
6
 
6
7
  export const validateSchemaInBlock: InBlockPayloadValidationFunction = async (
7
8
  payload,
8
9
  block: HydratedBlock,
9
- ): Promise<Error[]> => {
10
+ ): Promise<(InBlockPayloadValidationError | Error)[]> => {
10
11
  const errors: Error[] = []
11
12
  try {
12
13
  errors.push(...await validateTypedPayloadInBlock(payload, block, isSchemaPayload))
13
14
  } catch (e) {
14
- errors.push(new Error(`Failed validateSchemaInBlock: ${e instanceof Error ? e.message : String(e)}`))
15
+ errors.push(new InBlockPayloadValidationError(block, payload, `Failed validateSchemaInBlock: ${e instanceof Error ? e.message : String(e)}`))
15
16
  }
16
17
  return errors
17
18
  }
@@ -1,6 +1,8 @@
1
- import {
2
- type HydratedBlock, type InBlockPayloadValidationFunction, isTransfer,
1
+ import type {
2
+ HydratedBlock,
3
+ InBlockPayloadValidationFunction,
3
4
  } from '@xyo-network/xl1-protocol'
5
+ import { InBlockPayloadValidationError, isTransfer } from '@xyo-network/xl1-protocol'
4
6
 
5
7
  import { validateTypedPayloadInBlock } from '../lib/index.ts'
6
8
 
@@ -8,11 +10,11 @@ export const validateTransferInBlock: InBlockPayloadValidationFunction = async (
8
10
  payload,
9
11
  block: HydratedBlock,
10
12
  ): Promise<Error[]> => {
11
- const errors: Error[] = []
13
+ const errors: (InBlockPayloadValidationError | Error)[] = []
12
14
  try {
13
15
  errors.push(...await validateTypedPayloadInBlock(payload, block, isTransfer))
14
16
  } catch (e) {
15
- errors.push(new Error(`Failed validateTransferInBlock: ${e instanceof Error ? e.message : String(e)}`))
17
+ errors.push(new InBlockPayloadValidationError(block, payload, `Failed validateTransferInBlock: ${e instanceof Error ? e.message : String(e)}`))
16
18
  }
17
19
  return errors
18
20
  }
@@ -6,7 +6,8 @@ import type {
6
6
  InBlockPayloadValidationFunction,
7
7
  } from '@xyo-network/xl1-protocol'
8
8
  import {
9
- ChainStakeIntentSchema, HashSchema, TransferSchema,
9
+ ChainStakeIntentSchema, HashSchema, InBlockPayloadValidationError,
10
+ TransferSchema,
10
11
  } from '@xyo-network/xl1-protocol'
11
12
 
12
13
  import { validateTransactionInBlock } from './lib/index.ts'
@@ -25,17 +26,17 @@ const payloadValidators: Partial<Record<Schema, InBlockPayloadValidationFunction
25
26
  export const validatePayloadInBlock: InBlockPayloadValidationFunction = async (
26
27
  payload,
27
28
  block: HydratedBlock,
28
- ): Promise<Error[]> => {
29
- const errors: Error[] = []
29
+ ): Promise<(InBlockPayloadValidationError | Error)[]> => {
30
+ const errors: (InBlockPayloadValidationError | Error)[] = []
30
31
  try {
31
32
  const validator = payloadValidators[payload.schema]
32
33
  if (validator) {
33
34
  errors.push(...await validator(payload, block))
34
35
  } else {
35
- errors.push(new Error(`Unsupported payload schema: ${payload.schema}`))
36
+ errors.push(new InBlockPayloadValidationError(block, payload, `Unsupported payload schema: ${payload.schema}`))
36
37
  }
37
38
  } catch (e) {
38
- errors.push(new Error(`Failed validatePayloadInBlock: ${e instanceof Error ? e.message : String(e)}`))
39
+ errors.push(new InBlockPayloadValidationError(block, payload, `Failed validatePayloadInBlock: ${e instanceof Error ? e.message : String(e)}`))
39
40
  }
40
41
  return errors
41
42
  }
@@ -1,26 +1,27 @@
1
1
  import type { Address } from '@xylabs/hex'
2
- import type { HydratedBlock, HydratedBlockValidatorFunction } from '@xyo-network/xl1-protocol'
2
+ import type { HydratedBlock, HydratedBlockValidationFunction } from '@xyo-network/xl1-protocol'
3
+ import { HydratedBlockValidationError } from '@xyo-network/xl1-protocol'
3
4
 
4
5
  import { validateBlock } from '../block/index.ts'
5
6
  import { BoundWitnessReferencesValidator } from '../boundwitness/index.ts'
6
7
  import { PayloadsInBlockValidator } from './validators/index.ts'
7
8
 
8
- export const validateHydratedBlock: HydratedBlockValidatorFunction = async (
9
+ export const validateHydratedBlock: HydratedBlockValidationFunction = async (
9
10
  hydratedBlock: HydratedBlock,
10
11
  chainId?: Address,
11
- additionalValidators: HydratedBlockValidatorFunction[] = [],
12
- ): Promise<Error[]> => {
12
+ additionalValidators: HydratedBlockValidationFunction[] = [],
13
+ ): Promise<(HydratedBlockValidationError | Error)[]> => {
13
14
  const errors: Error[] = []
14
15
  try {
15
16
  errors.push(...await validateBlock(hydratedBlock[0], chainId))
16
- const validators: HydratedBlockValidatorFunction[] = [
17
+ const validators: HydratedBlockValidationFunction[] = [
17
18
  BoundWitnessReferencesValidator(),
18
19
  PayloadsInBlockValidator,
19
20
  ...additionalValidators,
20
21
  ]
21
22
  errors.push(...(await Promise.all(validators.map(v => v(hydratedBlock, chainId)))).flat())
22
23
  } catch (e) {
23
- errors.push(new Error(`Failed validateHydratedBlock: ${e instanceof Error ? e.message : String(e)}`))
24
+ errors.push(new HydratedBlockValidationError(hydratedBlock, `Failed validateHydratedBlock: ${e instanceof Error ? e.message : String(e)}`))
24
25
  }
25
26
  return errors
26
27
  }
@@ -2,15 +2,16 @@ import type { Hash } from '@xylabs/hex'
2
2
  import type { Payload, WithHashStorageMeta } from '@xyo-network/payload-model'
3
3
  import type {
4
4
  HydratedBlock,
5
- HydratedBlockValidatorFunction,
5
+ HydratedBlockValidationFunction,
6
6
  } from '@xyo-network/xl1-protocol'
7
+ import { HydratedBlockValidationError } from '@xyo-network/xl1-protocol'
7
8
 
8
9
  import { validatePayloadInBlock } from '../../elevatedPayload/validatePayloadInBlock.ts'
9
10
 
10
- export const PayloadsInBlockValidator: HydratedBlockValidatorFunction = async (
11
+ export const PayloadsInBlockValidator: HydratedBlockValidationFunction = async (
11
12
  [block, payloads]: HydratedBlock,
12
13
  ) => {
13
- const errors: Error[] = []
14
+ const errors: (HydratedBlockValidationError | Error)[] = []
14
15
  try {
15
16
  const payloadMap: Partial<Record<Hash, WithHashStorageMeta<Payload>>> = {}
16
17
  for (const payload of payloads) {
@@ -27,15 +28,15 @@ export const PayloadsInBlockValidator: HydratedBlockValidatorFunction = async (
27
28
  errors.push(...await validatePayloadInBlock(payload, [block, payloads]))
28
29
  delete remainingPayloads[hash]
29
30
  } else {
30
- errors.push(new Error(`missing payload ${hash} ${schema}`))
31
+ errors.push(new HydratedBlockValidationError([block, payloads], `missing payload ${hash} ${schema}`))
31
32
  }
32
33
  }
33
34
 
34
35
  if (Object.keys(remainingPayloads).length > 0) {
35
- errors.push(new Error(`extra payloads ${Object.keys(payloadMap).join(', ')}`))
36
+ errors.push(new HydratedBlockValidationError([block, payloads], `extra payloads ${Object.keys(payloadMap).join(', ')}`))
36
37
  }
37
38
  } catch (e) {
38
- errors.push(new Error(`Failed PayloadsInBlockValidator: ${e instanceof Error ? e.message : String(e)}`))
39
+ errors.push(new HydratedBlockValidationError([block, payloads], `Failed PayloadsInBlockValidator: ${e instanceof Error ? e.message : String(e)}`))
39
40
  }
40
41
 
41
42
  return errors
@@ -2,6 +2,7 @@ import type { Address } from '@xylabs/hex'
2
2
  import type {
3
3
  AccountBalanceService, HydratedBlock, HydratedBlockStateValidationFunction,
4
4
  } from '@xyo-network/xl1-protocol'
5
+ import { HydratedBlockStateValidationError } from '@xyo-network/xl1-protocol'
5
6
 
6
7
  import { validateHydratedBlock } from '../hydratedBlock/index.ts'
7
8
  import { RequiredBalanceBlockStateValidator } from './validators/index.ts'
@@ -11,7 +12,7 @@ export const validateHydratedBlockState: HydratedBlockStateValidationFunction =
11
12
  chainId: Address,
12
13
  services: { accountBalance: AccountBalanceService },
13
14
  additionalValidators: HydratedBlockStateValidationFunction[] = [],
14
- ): Promise<Error[]> => {
15
+ ): Promise<(HydratedBlockStateValidationError | Error)[]> => {
15
16
  const errors: Error[] = []
16
17
  try {
17
18
  errors.push(...await validateHydratedBlock(hydratedBlock, chainId))
@@ -21,7 +22,11 @@ export const validateHydratedBlockState: HydratedBlockStateValidationFunction =
21
22
  ]
22
23
  errors.push(...(await Promise.all(validators.map(v => v(hydratedBlock, chainId, services)))).flat())
23
24
  } catch (e) {
24
- errors.push(new Error(`Failed validateHydratedBlockState: ${e instanceof Error ? e.message : String(e)}`))
25
+ errors.push(new HydratedBlockStateValidationError(
26
+ chainId,
27
+ hydratedBlock,
28
+ `Failed validateHydratedBlockState: ${e instanceof Error ? e.message : String(e)}`,
29
+ ))
25
30
  }
26
31
  return errors
27
32
  }
@@ -4,13 +4,14 @@ import { XYO_ZERO_ADDRESS } from '@xyo-network/chain-utils'
4
4
  import type {
5
5
  AccountBalanceService, HydratedBlock, HydratedBlockStateValidationFunction,
6
6
  } from '@xyo-network/xl1-protocol'
7
+ import { HydratedBlockStateValidationError } from '@xyo-network/xl1-protocol'
7
8
 
8
9
  export const RequiredBalanceBlockStateValidator: HydratedBlockStateValidationFunction = async (
9
10
  block: HydratedBlock,
10
11
  chainId: Address,
11
12
  services: { accountBalance: AccountBalanceService },
12
13
  ) => {
13
- const errors: Error[] = []
14
+ const errors: (HydratedBlockStateValidationError | Error)[] = []
14
15
  try {
15
16
  // TODO: Filter by non-producer elevated payloads
16
17
  // to allow for transfers from ZERO address
@@ -23,16 +24,24 @@ export const RequiredBalanceBlockStateValidator: HydratedBlockStateValidationFun
23
24
  }
24
25
  }
25
26
  const previous = block[0].previous
26
- if (previous === null) return [new Error('Insufficient funds because first block')]
27
+ if (previous === null) return [new HydratedBlockStateValidationError(chainId, block, 'Insufficient funds because first block')]
27
28
 
28
29
  for (const [address, reqBalance] of Object.entries(requiredBalances) as [Address, bigint][]) {
29
30
  const balance = hexToBigInt(services.accountBalance.getBalance(address))
30
31
  if (address !== XYO_ZERO_ADDRESS && reqBalance > balance) {
31
- errors.push(new Error(`insufficient balance for ${address} ${balance} < ${requiredBalances[address]}`))
32
+ errors.push(new HydratedBlockStateValidationError(
33
+ chainId,
34
+ block,
35
+ `insufficient balance for ${address} ${balance} < ${requiredBalances[address]}`,
36
+ ))
32
37
  }
33
38
  }
34
39
  } catch (e) {
35
- errors.push(new Error(`Failed RequiredBalanceBlockStateValidator: ${e instanceof Error ? e.message : String(e)}`))
40
+ errors.push(new HydratedBlockStateValidationError(
41
+ chainId,
42
+ block,
43
+ `Failed RequiredBalanceBlockStateValidator: ${e instanceof Error ? e.message : String(e)}`,
44
+ ))
36
45
  }
37
46
  return await Promise.resolve(errors)
38
47
  }
@@ -1,5 +1,5 @@
1
1
  import type { Address } from '@xylabs/hex'
2
- import type { HydratedTransactionValidatorFunction, HydratedTransactionWithHashStorageMeta } from '@xyo-network/xl1-protocol'
2
+ import type { HydratedTransaction, HydratedTransactionValidationFunction } from '@xyo-network/xl1-protocol'
3
3
  import { isTransactionBoundWitness } from '@xyo-network/xl1-protocol'
4
4
 
5
5
  import {
@@ -8,16 +8,16 @@ import {
8
8
  } from './validators/index.ts'
9
9
 
10
10
  export async function validateTransaction(
11
- tx: HydratedTransactionWithHashStorageMeta,
11
+ tx: HydratedTransaction,
12
12
  chainId?: Address,
13
- additionalValidators: HydratedTransactionValidatorFunction[] = [],
14
- ): Promise<Error[]> {
13
+ additionalValidators: HydratedTransactionValidationFunction[] = [],
14
+ ) {
15
15
  try {
16
16
  if (!isTransactionBoundWitness(tx[0])) {
17
17
  return [new Error('failed isTransactionBoundWitness identity check')]
18
18
  }
19
19
 
20
- const validators: HydratedTransactionValidatorFunction[] = [
20
+ const validators: HydratedTransactionValidationFunction[] = [
21
21
  TransactionProtocolValidator,
22
22
  TransactionJsonSchemaValidator,
23
23
  TransactionDurationValidator,
@@ -1,20 +1,21 @@
1
1
  import type {
2
- HydratedTransaction, HydratedTransactionValidatorFunction, TransactionBoundWitness,
2
+ HydratedTransaction, HydratedTransactionValidationFunction, TransactionBoundWitness,
3
3
  } from '@xyo-network/xl1-protocol'
4
+ import { HydratedTransactionValidationError } from '@xyo-network/xl1-protocol'
4
5
 
5
- export const TransactionDurationValidator: HydratedTransactionValidatorFunction<TransactionBoundWitness> = (
6
- [tx]: HydratedTransaction,
7
- ): Error[] => {
8
- const errors: Error[] = []
6
+ export const TransactionDurationValidator: HydratedTransactionValidationFunction<TransactionBoundWitness> = (
7
+ tx: HydratedTransaction,
8
+ ) => {
9
+ const errors: (HydratedTransactionValidationError | Error)[] = []
9
10
  try {
10
- const { exp, nbf } = tx
11
- if (nbf < 0) errors.push(new Error('Transaction nbf must be positive'))
11
+ const { exp, nbf } = tx[0]
12
+ if (nbf < 0) errors.push(new HydratedTransactionValidationError(tx, 'Transaction nbf must be positive'))
12
13
 
13
- if (exp < 0) errors.push(new Error('Transaction exp must be positive'))
14
- if (exp <= nbf) errors.push(new Error('Transaction exp must greater than nbf'))
15
- if (exp - nbf > 10_000) errors.push(new Error('Transaction exp must not be too far in the future'))
14
+ if (exp < 0) errors.push(new HydratedTransactionValidationError(tx, 'Transaction exp must be positive'))
15
+ if (exp <= nbf) errors.push(new HydratedTransactionValidationError(tx, 'Transaction exp must greater than nbf'))
16
+ if (exp - nbf > 10_000) errors.push(new HydratedTransactionValidationError(tx, 'Transaction exp must not be too far in the future'))
16
17
  } catch (e) {
17
- errors.push(new Error(`Failed TransactionDurationValidator: ${e instanceof Error ? e.message : String(e)}`))
18
+ errors.push(new HydratedTransactionValidationError(tx, `Failed TransactionDurationValidator: ${e instanceof Error ? e.message : String(e)}`))
18
19
  }
19
20
 
20
21
  return errors
@@ -1,21 +1,21 @@
1
- import type { Promisable } from '@xylabs/promise'
2
1
  import { extractElevatedHashes } from '@xyo-network/chain-protocol'
3
2
  import type {
4
- HydratedTransactionValidatorFunction, HydratedTransactionWithHashStorageMeta, TransactionBoundWitness,
3
+ HydratedTransaction, HydratedTransactionValidationFunction, TransactionBoundWitness,
5
4
  } from '@xyo-network/xl1-protocol'
5
+ import { HydratedTransactionValidationError } from '@xyo-network/xl1-protocol'
6
6
 
7
- export const TransactionElevationValidator: HydratedTransactionValidatorFunction<TransactionBoundWitness> = (
8
- tx: HydratedTransactionWithHashStorageMeta,
9
- ): Promisable<Error[]> => {
10
- const errors: Error[] = []
7
+ export const TransactionElevationValidator: HydratedTransactionValidationFunction<TransactionBoundWitness> = (
8
+ tx: HydratedTransaction,
9
+ ) => {
10
+ const errors: (HydratedTransactionValidationError | Error)[] = []
11
11
  try {
12
12
  try {
13
13
  extractElevatedHashes(tx)
14
14
  } catch {
15
- errors.push(new Error('Hydrated transaction does not include all script hashes'))
15
+ errors.push(new HydratedTransactionValidationError(tx, 'Hydrated transaction does not include all script hashes'))
16
16
  }
17
17
  } catch (e) {
18
- errors.push(new Error(`Failed TransactionElevationValidator: ${e instanceof Error ? e.message : String(e)}`))
18
+ errors.push(new HydratedTransactionValidationError(tx, `Failed TransactionElevationValidator: ${e instanceof Error ? e.message : String(e)}`))
19
19
  }
20
20
  return errors
21
21
  }
@@ -1,19 +1,20 @@
1
1
  import { asAddress } from '@xylabs/hex'
2
2
  import { addressesContains } from '@xyo-network/boundwitness-validator'
3
3
  import type {
4
- HydratedTransaction, HydratedTransactionValidatorFunction, TransactionBoundWitness,
4
+ HydratedTransaction, HydratedTransactionValidationFunction, TransactionBoundWitness,
5
5
  } from '@xyo-network/xl1-protocol'
6
+ import { HydratedTransactionValidationError } from '@xyo-network/xl1-protocol'
6
7
 
7
- export const TransactionFromValidator: HydratedTransactionValidatorFunction<TransactionBoundWitness> = (
8
- [tx]: HydratedTransaction,
9
- ): Error[] => {
10
- const errors: Error[] = []
8
+ export const TransactionFromValidator: HydratedTransactionValidationFunction<TransactionBoundWitness> = (
9
+ tx: HydratedTransaction,
10
+ ) => {
11
+ const errors: (HydratedTransactionValidationError | Error)[] = []
11
12
  try {
12
- const from = asAddress(tx.from)
13
- if (from === undefined)errors.push(new Error('Transaction from is not a valid address'))
14
- else if (!addressesContains(tx, from)) errors.push(new Error('Transaction from address must be listed in addresses'))
13
+ const from = asAddress(tx[0].from)
14
+ if (from === undefined)errors.push(new HydratedTransactionValidationError(tx, 'Transaction from is not a valid address'))
15
+ else if (!addressesContains(tx[0], from)) errors.push(new HydratedTransactionValidationError(tx, 'Transaction from address must be listed in addresses'))
15
16
  } catch (e) {
16
- errors.push(new Error(`Failed TransactionFromValidator: ${e instanceof Error ? e.message : String(e)}`))
17
+ errors.push(new HydratedTransactionValidationError(tx, `Failed TransactionFromValidator: ${e instanceof Error ? e.message : String(e)}`))
17
18
  }
18
19
  return errors
19
20
  }