import { Ed25519 } from "@iota/crypto.js" ; import type { ReadStream , WriteStream } from "@iota/util.js" ; import bigInt from "big-integer" ; import { IIndexationPayload , INDEXATION_PAYLOAD_TYPE } from "../models/IIndexationPayload" ; import { IMilestonePayload , MILESTONE_PAYLOAD_TYPE } from "../models/IMilestonePayload" ; import { IReceiptPayload , RECEIPT_PAYLOAD_TYPE } from "../models/IReceiptPayload" ; import { TRANSACTION_ESSENCE_TYPE } from "../models/ITransactionEssence" ; import { ITransactionPayload , TRANSACTION_PAYLOAD_TYPE } from "../models/ITransactionPayload" ; import { ITreasuryTransactionPayload , TREASURY_TRANSACTION_PAYLOAD_TYPE } from "../models/ITreasuryTransactionPayload" ; import type { ITypeBase } from "../models/ITypeBase" ; import { BYTE_SIZE , MERKLE_PROOF_LENGTH , MESSAGE_ID_LENGTH , STRING_LENGTH , TYPE_LENGTH , UINT16_SIZE , UINT32_SIZE , UINT64_SIZE } from "./common" ; import { deserializeFunds , MIN_MIGRATED_FUNDS_LENGTH , serializeFunds } from "./funds" ; import { deserializeTreasuryInput , MIN_TREASURY_INPUT_LENGTH , serializeTreasuryInput } from "./input" ; import { MAX_NUMBER_PARENTS , MIN_NUMBER_PARENTS } from "./message" ; import { deserializeTreasuryOutput , MIN_TREASURY_OUTPUT_LENGTH , serializeTreasuryOutput } from "./output" ; import { deserializeTransactionEssence , serializeTransactionEssence } from "./transaction" ; import { deserializeUnlockBlocks , serializeUnlockBlocks } from "./unlockBlock" ; /**
 * The minimum length of a payload binary representation.
 */ export const MIN_PAYLOAD_LENGTH = TYPE_LENGTH ; /**
 * The minimum length of a milestone payload binary representation.
 */ export const MIN_MILESTONE_PAYLOAD_LENGTH = MIN_PAYLOAD_LENGTH + UINT32_SIZE + UINT64_SIZE + MESSAGE_ID_LENGTH + MESSAGE_ID_LENGTH + MERKLE_PROOF_LENGTH + 2 * UINT32_SIZE + BYTE_SIZE + Ed25519 . PUBLIC_KEY_SIZE + BYTE_SIZE + Ed25519 . SIGNATURE_SIZE ; /**
 * The minimum length of an indexation payload binary representation.
 */ export const MIN_INDEXATION_PAYLOAD_LENGTH = MIN_PAYLOAD_LENGTH + STRING_LENGTH + 1 + STRING_LENGTH ; /**
 * The minimum length of a transaction payload binary representation.
 */ export const MIN_TRANSACTION_PAYLOAD_LENGTH = MIN_PAYLOAD_LENGTH + UINT32_SIZE ; /**
 * The minimum length of a receipt payload binary representation.
 */ export const MIN_RECEIPT_PAYLOAD_LENGTH = MIN_PAYLOAD_LENGTH + UINT32_SIZE + UINT16_SIZE + MIN_MIGRATED_FUNDS_LENGTH ; /**
 * The minimum length of a treasure transaction payload binary representation.
 */ export const MIN_TREASURY_TRANSACTION_PAYLOAD_LENGTH = MIN_PAYLOAD_LENGTH + MIN_TREASURY_INPUT_LENGTH + MIN_TREASURY_OUTPUT_LENGTH ; /**
 * The minimum length of a indexation key.
 */ export const MIN_INDEXATION_KEY_LENGTH = 1 ; /**
 * The maximum length of a indexation key.
 */ export const MAX_INDEXATION_KEY_LENGTH = 64 ; param readStream returns export function deserializePayload ( readStream ) { const payloadLength = readStream . readUInt32 ( "payload.length" ) ; if ( ! readStream . hasRemaining ( payloadLength ) ) { throw new Error ( `Payload length ${ payloadLength } exceeds the remaining data ${ readStream . unused ( ) }` ) ; } let payload ; if ( payloadLength > 0 ) { const payloadType = readStream . readUInt32 ( "payload.type" , false ) ; if ( payloadType === TRANSACTION_PAYLOAD_TYPE ) { payload = deserializeTransactionPayload ( readStream ) ; } else if ( payloadType === MILESTONE_PAYLOAD_TYPE ) { payload = deserializeMilestonePayload ( readStream ) ; } else if ( payloadType === INDEXATION_PAYLOAD_TYPE ) { payload = deserializeIndexationPayload ( readStream ) ; } else if ( payloadType === RECEIPT_PAYLOAD_TYPE ) { payload = deserializeReceiptPayload ( readStream ) ; } else if ( payloadType === TREASURY_TRANSACTION_PAYLOAD_TYPE ) { payload = deserializeTreasuryTransactionPayload ( readStream ) ; } else { throw new Error ( `Unrecognized payload type ${ payloadType }` ) ; } } return payload ; } param writeStream param object export function serializePayload ( writeStream , object ) { const payloadLengthWriteIndex = writeStream . getWriteIndex ( ) ; writeStream . writeUInt32 ( "payload.length" , 0 ) ; if ( ! object ) { } else if ( object . type === TRANSACTION_PAYLOAD_TYPE ) { serializeTransactionPayload ( writeStream , object ) ; } else if ( object . type === MILESTONE_PAYLOAD_TYPE ) { serializeMilestonePayload ( writeStream , object ) ; } else if ( object . type === INDEXATION_PAYLOAD_TYPE ) { serializeIndexationPayload ( writeStream , object ) ; } else if ( object . type === RECEIPT_PAYLOAD_TYPE ) { serializeReceiptPayload ( writeStream , object ) ; } else if ( object . type === TREASURY_TRANSACTION_PAYLOAD_TYPE ) { serializeTreasuryTransactionPayload ( writeStream , object ) ; } else { throw new Error ( `Unrecognized transaction type ${ ( object as ITypeBase < number > ) . type }` ) ; } const endOfPayloadWriteIndex = writeStream . getWriteIndex ( ) ; writeStream . setWriteIndex ( payloadLengthWriteIndex ) ; writeStream . writeUInt32 ( "payload.length" , endOfPayloadWriteIndex - payloadLengthWriteIndex - UINT32_SIZE ) ; writeStream . setWriteIndex ( endOfPayloadWriteIndex ) ; } param readStream returns export function deserializeTransactionPayload ( readStream ) { if ( ! readStream . hasRemaining ( MIN_TRANSACTION_PAYLOAD_LENGTH ) ) { throw new Error ( `Transaction Payload data is ${ readStream . length ( ) } in length which is less than the minimimum size required of ${ MIN_TRANSACTION_PAYLOAD_LENGTH }` ) ; } const type = readStream . readUInt32 ( "payloadTransaction.type" ) ; if ( type !== TRANSACTION_PAYLOAD_TYPE ) { throw new Error ( `Type mismatch in payloadTransaction ${ type }` ) ; } const essenceType = readStream . readByte ( "payloadTransaction.essenceType" , false ) ; let essence ; let unlockBlocks ; if ( essenceType === TRANSACTION_ESSENCE_TYPE ) { essence = deserializeTransactionEssence ( readStream ) ; unlockBlocks = deserializeUnlockBlocks ( readStream ) ; } else { throw new Error ( `Unrecognized transaction essence type ${ type }` ) ; } return { type : TRANSACTION_PAYLOAD_TYPE , essence , unlockBlocks } ; } param writeStream param object export function serializeTransactionPayload ( writeStream , object ) { writeStream . writeUInt32 ( "payloadMilestone.type" , object . type ) ; if ( object . type === TRANSACTION_PAYLOAD_TYPE ) { serializeTransactionEssence ( writeStream , object . essence ) ; serializeUnlockBlocks ( writeStream , object . unlockBlocks ) ; } else { throw new Error ( `Unrecognized transaction type ${ object . type }` ) ; } } param readStream returns export function deserializeMilestonePayload ( readStream ) { if ( ! readStream . hasRemaining ( MIN_MILESTONE_PAYLOAD_LENGTH ) ) { throw new Error ( `Milestone Payload data is ${ readStream . length ( ) } in length which is less than the minimimum size required of ${ MIN_MILESTONE_PAYLOAD_LENGTH }` ) ; } const type = readStream . readUInt32 ( "payloadMilestone.type" ) ; if ( type !== MILESTONE_PAYLOAD_TYPE ) { throw new Error ( `Type mismatch in payloadMilestone ${ type }` ) ; } const index = readStream . readUInt32 ( "payloadMilestone.index" ) ; const timestamp = readStream . readUInt64 ( "payloadMilestone.timestamp" ) ; const numParents = readStream . readByte ( "payloadMilestone.numParents" ) ; const parentMessageIds = [ ] ; for ( let i = 0 ; i < numParents ; i ++ ) { const parentMessageId = readStream . readFixedHex ( `payloadMilestone.parentMessageId${ i + 1 }` , MESSAGE_ID_LENGTH ) ; parentMessageIds . push ( parentMessageId ) ; } const inclusionMerkleProof = readStream . readFixedHex ( "payloadMilestone.inclusionMerkleProof" , MERKLE_PROOF_LENGTH ) ; const nextPoWScore = readStream . readUInt32 ( "payloadMilestone.nextPoWScore" ) ; const nextPoWScoreMilestoneIndex = readStream . readUInt32 ( "payloadMilestone.nextPoWScoreMilestoneIndex" ) ; const publicKeysCount = readStream . readByte ( "payloadMilestone.publicKeysCount" ) ; const publicKeys = [ ] ; for ( let i = 0 ; i < publicKeysCount ; i ++ ) { publicKeys . push ( readStream . readFixedHex ( "payloadMilestone.publicKey" , Ed25519 . PUBLIC_KEY_SIZE ) ) ; } const receipt = deserializePayload ( readStream ) as IReceiptPayload ; if ( receipt && receipt . type !== RECEIPT_PAYLOAD_TYPE ) { throw new Error ( "Milestones only support embedded receipt payload type" ) ; } const signaturesCount = readStream . readByte ( "payloadMilestone.signaturesCount" ) ; const signatures = [ ] ; for ( let i = 0 ; i < signaturesCount ; i ++ ) { signatures . push ( readStream . readFixedHex ( "payloadMilestone.signature" , Ed25519 . SIGNATURE_SIZE ) ) ; } return { type : MILESTONE_PAYLOAD_TYPE , index , timestamp : Number ( timestamp ) , parentMessageIds , inclusionMerkleProof , nextPoWScore , nextPoWScoreMilestoneIndex , publicKeys , receipt , signatures } ; } param writeStream param object export function serializeMilestonePayload ( writeStream , object ) { writeStream . writeUInt32 ( "payloadMilestone.type" , object . type ) ; writeStream . writeUInt32 ( "payloadMilestone.index" , object . index ) ; writeStream . writeUInt64 ( "payloadMilestone.timestamp" , bigInt ( object . timestamp ) ) ; if ( object . parentMessageIds . length < MIN_NUMBER_PARENTS ) { throw new Error ( `A minimum of ${ MIN_NUMBER_PARENTS } parents is allowed, you provided ${ object . parentMessageIds . length }` ) ; } if ( object . parentMessageIds . length > MAX_NUMBER_PARENTS ) { throw new Error ( `A maximum of ${ MAX_NUMBER_PARENTS } parents is allowed, you provided ${ object . parentMessageIds . length }` ) ; } if ( new Set ( object . parentMessageIds ) . size !== object . parentMessageIds . length ) { throw new Error ( "The milestone parents must be unique" ) ; } const sorted = object . parentMessageIds . slice ( ) . sort ( ) ; writeStream . writeByte ( "payloadMilestone.numParents" , object . parentMessageIds . length ) ; for ( let i = 0 ; i < object . parentMessageIds . length ; i ++ ) { if ( sorted [ i ] !== object . parentMessageIds [ i ] ) { throw new Error ( "The milestone parents must be lexographically sorted" ) ; } writeStream . writeFixedHex ( `payloadMilestone.parentMessageId${ i + 1 }` , MESSAGE_ID_LENGTH , object . parentMessageIds [ i ] ) ; } writeStream . writeFixedHex ( "payloadMilestone.inclusionMerkleProof" , MERKLE_PROOF_LENGTH , object . inclusionMerkleProof ) ; writeStream . writeUInt32 ( "payloadMilestone.nextPoWScore" , object . nextPoWScore ) ; writeStream . writeUInt32 ( "payloadMilestone.nextPoWScoreMilestoneIndex" , object . nextPoWScoreMilestoneIndex ) ; writeStream . writeByte ( "payloadMilestone.publicKeysCount" , object . publicKeys . length ) ; for ( let i = 0 ; i < object . publicKeys . length ; i ++ ) { writeStream . writeFixedHex ( "payloadMilestone.publicKey" , Ed25519 . PUBLIC_KEY_SIZE , object . publicKeys [ i ] ) ; } serializePayload ( writeStream , object . receipt ) ; writeStream . writeByte ( "payloadMilestone.signaturesCount" , object . signatures . length ) ; for ( let i = 0 ; i < object . signatures . length ; i ++ ) { writeStream . writeFixedHex ( "payloadMilestone.signature" , Ed25519 . SIGNATURE_SIZE , object . signatures [ i ] ) ; } } param readStream returns export function deserializeIndexationPayload ( readStream ) { if ( ! readStream . hasRemaining ( MIN_INDEXATION_PAYLOAD_LENGTH ) ) { throw new Error ( `Indexation Payload data is ${ readStream . length ( ) } in length which is less than the minimimum size required of ${ MIN_INDEXATION_PAYLOAD_LENGTH }` ) ; } const type = readStream . readUInt32 ( "payloadIndexation.type" ) ; if ( type !== INDEXATION_PAYLOAD_TYPE ) { throw new Error ( `Type mismatch in payloadIndexation ${ type }` ) ; } const indexLength = readStream . readUInt16 ( "payloadIndexation.indexLength" ) ; const index = readStream . readFixedHex ( "payloadIndexation.index" , indexLength ) ; const dataLength = readStream . readUInt32 ( "payloadIndexation.dataLength" ) ; const data = readStream . readFixedHex ( "payloadIndexation.data" , dataLength ) ; return { type : INDEXATION_PAYLOAD_TYPE , index , data } ; } param writeStream param object export function serializeIndexationPayload ( writeStream , object ) { if ( object . index . length < MIN_INDEXATION_KEY_LENGTH ) { throw new Error ( `The indexation key length is ${ object . index . length }, which is below the minimum size of ${ MIN_INDEXATION_KEY_LENGTH }` ) ; } if ( object . index . length / 2 > MAX_INDEXATION_KEY_LENGTH ) { throw new Error ( `The indexation key length is ${ object . index . length / 2 }, which exceeds the maximum size of ${ MAX_INDEXATION_KEY_LENGTH }` ) ; } writeStream . writeUInt32 ( "payloadIndexation.type" , object . type ) ; writeStream . writeUInt16 ( "payloadIndexation.indexLength" , object . index . length / 2 ) ; writeStream . writeFixedHex ( "payloadIndexation.index" , object . index . length / 2 , object . index ) ; if ( object . data ) { writeStream . writeUInt32 ( "payloadIndexation.dataLength" , object . data . length / 2 ) ; writeStream . writeFixedHex ( "payloadIndexation.data" , object . data . length / 2 , object . data ) ; } else { writeStream . writeUInt32 ( "payloadIndexation.dataLength" , 0 ) ; } } param readStream returns export function deserializeReceiptPayload ( readStream ) { if ( ! readStream . hasRemaining ( MIN_RECEIPT_PAYLOAD_LENGTH ) ) { throw new Error ( `Receipt Payload data is ${ readStream . length ( ) } in length which is less than the minimimum size required of ${ MIN_RECEIPT_PAYLOAD_LENGTH }` ) ; } const type = readStream . readUInt32 ( "payloadReceipt.type" ) ; if ( type !== RECEIPT_PAYLOAD_TYPE ) { throw new Error ( `Type mismatch in payloadReceipt ${ type }` ) ; } const migratedAt = readStream . readUInt32 ( "payloadReceipt.migratedAt" ) ; const final = readStream . readBoolean ( "payloadReceipt.final" ) ; const funds = deserializeFunds ( readStream ) ; const treasuryTransactionPayload = deserializePayload ( readStream ) as ITreasuryTransactionPayload ; if ( ! treasuryTransactionPayload || treasuryTransactionPayload . type !== TREASURY_TRANSACTION_PAYLOAD_TYPE ) { throw new Error ( `payloadReceipts can only contain treasury payloads ${ type }` ) ; } return { type : RECEIPT_PAYLOAD_TYPE , migratedAt , final , funds , transaction : treasuryTransactionPayload } ; } param writeStream param object export function serializeReceiptPayload ( writeStream , object ) { writeStream . writeUInt32 ( "payloadReceipt.type" , object . type ) ; writeStream . writeUInt32 ( "payloadReceipt.migratedAt" , object . migratedAt ) ; writeStream . writeBoolean ( "payloadReceipt.final" , object . final ) ; serializeFunds ( writeStream , object . funds ) ; serializePayload ( writeStream , object . transaction ) ; } param readStream returns export function deserializeTreasuryTransactionPayload ( readStream ) { if ( ! readStream . hasRemaining ( MIN_TREASURY_TRANSACTION_PAYLOAD_LENGTH ) ) { throw new Error ( `Treasure Transaction Payload data is ${ readStream . length ( ) } in length which is less than the minimimum size required of ${ MIN_TREASURY_TRANSACTION_PAYLOAD_LENGTH }` ) ; } const type = readStream . readUInt32 ( "payloadTreasuryTransaction.type" ) ; if ( type !== TREASURY_TRANSACTION_PAYLOAD_TYPE ) { throw new Error ( `Type mismatch in payloadTreasuryTransaction ${ type }` ) ; } const input = deserializeTreasuryInput ( readStream ) ; const output = deserializeTreasuryOutput ( readStream ) ; return { type : TREASURY_TRANSACTION_PAYLOAD_TYPE , input , output } ; } param writeStream param object export function serializeTreasuryTransactionPayload ( writeStream , object ) { writeStream . writeUInt32 ( "payloadTreasuryTransaction.type" , object . type ) ; serializeTreasuryInput ( writeStream , object . input ) ; serializeTreasuryOutput ( writeStream , object . output ) ; }