diff --git a/src/fs/challenge.ts b/src/fs/challenge.ts new file mode 100644 index 00000000..762af285 --- /dev/null +++ b/src/fs/challenge.ts @@ -0,0 +1,97 @@ +import { Address } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { + dateToUnixTime, + decodeAddress, + decodeVarBytes, + decodeVarUint, + serializeAddress, + serializeVarUint, + unixTimeToDate +} from './utils'; + +export class Challenge { + static deserializeHex(hex: string): Challenge { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + const fileOwner = decodeAddress(sr); + const nodeAddr = decodeAddress(sr); + const challengeHeight = decodeVarUint(sr); + const reward = decodeVarUint(sr); + const expiredTime = unixTimeToDate(decodeVarUint(sr)); + const state = decodeVarUint(sr); + + return new Challenge( + fileHash, + fileOwner, + nodeAddr, + challengeHeight, + reward, + expiredTime, + state + ); + } + public constructor( + public readonly fileHash: string, + public readonly fileOwner: Address = new Address('0'.repeat(40)), + public readonly nodeAddr: Address = new Address('0'.repeat(40)), + public readonly challengeHeight: number = 0, + public readonly reward: number = 0, + public readonly expiredTime: Date = new Date(), + public readonly state: number = 0 + ) { } + + public serializeHex(): string { + return ( + hex2VarBytes(this.fileHash) + + serializeAddress(this.fileOwner) + + serializeAddress(this.nodeAddr) + + serializeVarUint(this.challengeHeight) + + serializeVarUint(this.reward) + + serializeVarUint(dateToUnixTime(this.expiredTime)) + + serializeVarUint(this.state) + ); + } + + public export() { + return { + fileHash: this.fileHash, + fileOwner: this.fileOwner.value, + nodeAddr: this.nodeAddr.value, + challengeHeight: this.challengeHeight, + reward: this.reward, + expiredTime: this.expiredTime, + state: this.state + }; + } +} + +export class ChallengeList { + + static deserializeHex(hex: string): ChallengeList { + const sr: StringReader = new StringReader(hex); + const challenges: Challenge[] = []; + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const challenge = Challenge.deserializeHex(decodeVarBytes(sr)); + challenges.push(challenge); + } + return new ChallengeList(challenges); + } + public constructor(public challenges: Challenge[]) { } + + public serializeHex(): string { + let str = ''; + str += serializeVarUint(this.challenges.length); + for (const challenge of this.challenges) { + str += hex2VarBytes(challenge.serializeHex()); + } + return str; + } + + public export() { + return { + challenges: this.challenges.map((challenge) => challenge.export()) + }; + } +} diff --git a/src/fs/fileDel.ts b/src/fs/fileDel.ts new file mode 100644 index 00000000..9d70853b --- /dev/null +++ b/src/fs/fileDel.ts @@ -0,0 +1,41 @@ +import { hex2VarBytes, StringReader } from '../utils'; +import { decodeVarBytes, decodeVarUint, serializeVarUint } from './utils'; + +export class FileDel { + static deserializeHex(hex: string): FileDel { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + return new FileDel(fileHash); + } + public constructor( + public readonly fileHash: string + ) { } + + public serializeHex(): string { + return hex2VarBytes(this.fileHash); + } +} + +export class FileDelList { + static deserializeHex(hex: string): FileDelList { + const list: FileDel[] = []; + const sr: StringReader = new StringReader(hex); + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const del = FileDel.deserializeHex(sr.readNextBytes()); + list.push(del); + } + return new FileDelList(list); + } + public constructor( + public readonly filesDel: FileDel[] = [] + ) { } + + public serializeHex(): string { + let str = serializeVarUint(this.filesDel.length); + for (const fileDel of this.filesDel) { + str += hex2VarBytes(fileDel.serializeHex()); + } + return str; + } +} diff --git a/src/fs/fileHash.ts b/src/fs/fileHash.ts new file mode 100644 index 00000000..9fcd248d --- /dev/null +++ b/src/fs/fileHash.ts @@ -0,0 +1,52 @@ +import { hex2VarBytes, hexstr2str, StringReader } from '../utils'; +import { decodeVarBytes, decodeVarUint, serializeUint64 } from './utils'; + +export class FileHash { + static deserializeHex(hex: string): FileHash { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + return new FileHash(fileHash); + } + public constructor( + public readonly fHash: string + ) { } + + public serializeHex(): string { + return hex2VarBytes(this.fHash); + } + + public export() { + return { + fHash: this.fHash + }; + } +} + +export class FileHashList { + static deserializeHex(hex: string): FileHashList { + const sr: StringReader = new StringReader(hex); + const count = decodeVarUint(sr); + const hashes: FileHash[] = []; + for (let i = 0; i < count; i++) { + hashes.push(new FileHash(hexstr2str(decodeVarBytes(sr)))); + } + return new FileHashList(hashes); + } + public constructor( + public readonly filesH: FileHash[] + ) { } + + public serializeHex(): string { + let str = serializeUint64(this.filesH.length); + for (const fileHash of this.filesH) { + str += hex2VarBytes(fileHash.fHash); + } + return str; + } + + public export() { + return { + filesH: this.filesH.map((fileHash) => fileHash.export()) + }; + } +} diff --git a/src/fs/fileInfo.ts b/src/fs/fileInfo.ts new file mode 100644 index 00000000..1f05cc75 --- /dev/null +++ b/src/fs/fileInfo.ts @@ -0,0 +1,124 @@ +import { Address } from '../crypto'; +import { bool2VarByte, hex2VarBytes, num2VarInt, StringReader } from '../utils'; +import { dateToUnixTime, decodeAddress, decodeBool, decodeVarBytes, + decodeVarUint, serializeAddress, serializeVarUint, unixTimeToDate } from './utils'; + +export class FileInfo { + static deserializeHex(hex: string): FileInfo { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + const fileOwner = decodeAddress(sr); + const fileDesc = decodeVarBytes(sr); + const fileBlockCount = decodeVarUint(sr); + const realFileSize = decodeVarUint(sr); + const copyNumber = decodeVarUint(sr); + const payAmount = decodeVarUint(sr); + const restAmount = decodeVarUint(sr); + const firstPdp = decodeBool(sr); + const timeStart = unixTimeToDate(decodeVarUint(sr)); + const timeExpired = unixTimeToDate(decodeVarUint(sr)); + const beginHeight = decodeVarUint(sr); + const expiredHeight = decodeVarUint(sr); + const pdpParam = decodeVarBytes(sr); + const validFlag = decodeBool(sr); + const currFeeRate = decodeVarUint(sr) + const storageType = decodeVarUint(sr); + return new FileInfo( + fileHash, fileOwner, fileDesc, fileBlockCount, realFileSize, copyNumber, payAmount, restAmount, + firstPdp, timeStart, timeExpired, beginHeight, expiredHeight, pdpParam, validFlag, currFeeRate, storageType + ); + } + public constructor( + public readonly fileHash: string, + public readonly fileOwner: Address, + public readonly fileDesc: string, + public readonly fileBlockCount: number, + public readonly realFileSize: number, + public readonly copyNumber: number, + public readonly payAmount: number, + public readonly restAmount: number, + public readonly firstPdp: boolean, + public readonly timeStart: Date, + public readonly timeExpired: Date, + public readonly beginHeight: number, + public readonly expiredHeight: number, + public readonly pdpParam: string, + public readonly validFlag: boolean, + public readonly currFeeRate: number, + public readonly storageType: number + ) { } + + public serializeHex(): string { + return hex2VarBytes(this.fileHash) + + serializeAddress(this.fileOwner) + + hex2VarBytes(this.fileDesc) + + serializeVarUint(this.fileBlockCount) + + serializeVarUint(this.realFileSize) + + serializeVarUint(this.copyNumber) + + serializeVarUint(this.payAmount) + + serializeVarUint(this.restAmount) + + bool2VarByte(this.firstPdp) + + serializeVarUint(dateToUnixTime(this.timeStart)) + + serializeVarUint(dateToUnixTime(this.timeExpired)) + + serializeVarUint(this.beginHeight) + + serializeVarUint(this.expiredHeight) + + hex2VarBytes(this.pdpParam) + + bool2VarByte(this.validFlag) + + serializeVarUint(this.currFeeRate) + + serializeVarUint(this.storageType); + } + + public export() { + return { + fileHash: this.fileHash, + fileOwner: this.fileOwner.value, + fileDesc: this.fileDesc, + fileBlockCount: this.fileBlockCount, + realFileSize: this.realFileSize, + copyNumber: this.copyNumber, + payAmount: this.payAmount, + restAmount: this.restAmount, + firstPdp: this.firstPdp, + timeStart: this.timeStart, + timeExpired: this.timeExpired, + beginHeight: this.beginHeight, + expiredHeight: this.expiredHeight, + pdpParam: this.pdpParam, + validFlag: this.validFlag, + currFeeRate: this.currFeeRate, + storageType: this.storageType + }; + } +} + +export class FileInfoList { + static deserializeHex(hex: string): FileInfoList { + const list: FileInfo[] = []; + const sr: StringReader = new StringReader(hex); + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const item = FileInfo.deserializeHex(sr.readNextBytes()); + list.push(item); + } + return new FileInfoList(list); + } + public constructor( + public readonly filesI: FileInfo[] = [] + ) { } + + public serializeHex(): string { + let str = serializeVarUint(this.filesI.length); + for (const fileInfo of this.filesI) { + const fileInfoHex = fileInfo.serializeHex(); + const hexLen = num2VarInt(fileInfoHex.length / 2); + str += hexLen + fileInfoHex; + } + return str; + } + + public export() { + return { + filesI: this.filesI.map((fileInfo) => fileInfo.export()) + }; + } +} diff --git a/src/fs/filePdpData.ts b/src/fs/filePdpData.ts new file mode 100644 index 00000000..b0d860d6 --- /dev/null +++ b/src/fs/filePdpData.ts @@ -0,0 +1,29 @@ +import { Address } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { decodeAddress, decodeVarBytes, decodeVarUint, serializeUint64 } from './utils'; + +export class FilePdpData { + static deserializeHex(hex: string): FilePdpData { + const sr: StringReader = new StringReader(hex); + const nodeAddr = decodeAddress(sr); + const fileHash = decodeVarBytes(sr); + const proveData = decodeVarBytes(sr); + const challengeHeight = decodeVarUint(sr); + return new FilePdpData(nodeAddr, fileHash, proveData, challengeHeight); + } + public constructor( + public readonly nodeAddr: Address, + public readonly fileHash: string, + public readonly proveData: string, + public readonly challengeHeight: number + ) { } + + public serializeHex(): string { + let str = ''; + str += this.nodeAddr.serialize() + + hex2VarBytes(this.fileHash) + + hex2VarBytes(this.proveData) + + serializeUint64(this.challengeHeight); + return str; + } +} diff --git a/src/fs/fileReadSettleSlice.ts b/src/fs/fileReadSettleSlice.ts new file mode 100644 index 00000000..3bb2f925 --- /dev/null +++ b/src/fs/fileReadSettleSlice.ts @@ -0,0 +1,77 @@ +import { Address, PrivateKey, PublicKey, Signature } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { decodeAddress, decodeVarBytes, decodeVarUint, serializeAddress, serializeVarUint } from './utils'; +export class FileReadSettleSlice { + static genFileReadSettleSlice( + fileHash: string, + payTo: Address, + sliceId: number, + pledgeHeight: number, + privateKey: PrivateKey + ): FileReadSettleSlice { + const pubKey = privateKey.getPublicKey(); + const payFrom = Address.fromPubKey(pubKey); + const settleSlice = new FileReadSettleSlice(fileHash, payFrom, payTo, sliceId, pledgeHeight); + const signData = privateKey.sign(settleSlice.serializeHex()); + settleSlice.signature = signData; + settleSlice.publicKey = pubKey; + return settleSlice; + } + static deserializeHex(hex: string): FileReadSettleSlice { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + const payFrom = decodeAddress(sr); + const payTo = decodeAddress(sr); + const sliceId = decodeVarUint(sr); + const pledgeHeight = decodeVarUint(sr); + const sigHex = decodeVarBytes(sr); + const pubKeyHex = decodeVarBytes(sr); + const sig = Signature.deserializeHex(sigHex); + const pubKey = PublicKey.deserializeHex(new StringReader(pubKeyHex)); + return new FileReadSettleSlice(fileHash, payFrom, payTo, sliceId, pledgeHeight, + sig, pubKey); + } + + public constructor( + public readonly fileHash: string, + public readonly payFrom: Address, + public readonly payTo: Address, + public readonly sliceId: number, + public readonly pledgeHeight: number, + public signature?: Signature, + public publicKey?: PublicKey + ) {} + + public verify(): boolean { + if (!this.publicKey || !this.signature) { + return false; + } + return this.publicKey.verify(this.serializeHexWithoutVerifyInfo() + '00' + '00', this.signature); + } + + public serializeHexWithoutVerifyInfo(): string { + return hex2VarBytes(this.fileHash) + + serializeAddress(this.payFrom) + + serializeAddress(this.payTo) + + serializeVarUint(this.sliceId) + + serializeVarUint(this.pledgeHeight); + } + + public serializeHex(): string { + return this.serializeHexWithoutVerifyInfo() + + (this.signature ? hex2VarBytes(this.signature.value) : '00') + + (this.publicKey ? this.publicKey.serializeHex() : '00'); + } + + public export() { + return { + fileHash: this.fileHash, + payFrom: this.payFrom.value, + payTo: this.payTo.value, + sliceId: this.sliceId, + pledgeHeight: this.pledgeHeight, + signature: this.signature ? this.signature.serializeHex() : '', + publicKey: this.publicKey ? this.publicKey.serializeHex() : '' + }; + } +} diff --git a/src/fs/fileRenew.ts b/src/fs/fileRenew.ts new file mode 100644 index 00000000..d2441eeb --- /dev/null +++ b/src/fs/fileRenew.ts @@ -0,0 +1,52 @@ +import { Address } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { dateToUnixTime, decodeAddress, decodeVarBytes, decodeVarUint, + serializeAddress, serializeVarUint, unixTimeToDate } from './utils'; + +export class FileRenew { + static deserializeHex(hex: string): FileRenew { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + const fileOwner = decodeAddress(sr); + const payer = decodeAddress(sr); + const newTimeExpired = unixTimeToDate(decodeVarUint(sr)); + return new FileRenew(fileHash, fileOwner, payer, newTimeExpired); + } + public constructor( + public readonly fileHash: string, + public readonly fileOwner: Address, + public readonly payer: Address, + public readonly newTimeExpired: Date + ) { } + + public serializeHex(): string { + return hex2VarBytes(this.fileHash) + + serializeAddress(this.fileOwner) + + serializeAddress(this.payer) + + serializeVarUint(dateToUnixTime(this.newTimeExpired)); + } +} + +export class FileRenewList { + static deserializeHex(hex: string): FileRenewList { + const list: FileRenew[] = []; + const sr: StringReader = new StringReader(hex); + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const item = FileRenew.deserializeHex(sr.readNextBytes()); + list.push(item); + } + return new FileRenewList(list); + } + public constructor( + public readonly filesRenew: FileRenew[] = [] + ) { } + + public serializeHex(): string { + let str = serializeVarUint(this.filesRenew.length); + for (const fileRenew of this.filesRenew) { + str += hex2VarBytes(fileRenew.serializeHex()); + } + return str; + } +} diff --git a/src/fs/fileTransfer.ts b/src/fs/fileTransfer.ts new file mode 100644 index 00000000..3c3ec9fe --- /dev/null +++ b/src/fs/fileTransfer.ts @@ -0,0 +1,50 @@ +import { Address } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { decodeAddress, decodeVarBytes, decodeVarUint, serializeAddress, serializeVarUint } from './utils'; + +export class FileTransfer { + static deserializeHex(hex: string): FileTransfer { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + const oriOwner = decodeAddress(sr); + const newOwner = decodeAddress(sr); + return new FileTransfer(fileHash, oriOwner, newOwner); + } + public constructor( + public readonly fileHash: string, + public readonly oriOwner: Address, + public readonly newOwner: Address + ) { } + + public serializeHex(): string { + return hex2VarBytes(this.fileHash) + + serializeAddress(this.oriOwner) + + serializeAddress(this.newOwner); + } +} + +export class FileTransferList { + static deserializeHex(hex: string): FileTransferList { + const list: FileTransfer[] = []; + const sr: StringReader = new StringReader(hex); + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const item = FileTransfer.deserializeHex(sr.readNextBytes()); + list.push(item); + } + return new FileTransferList(list); + } + public constructor( + public readonly filesTransfer: FileTransfer[] = [] + ) { } + + public serializeHex(): string { + let str = serializeVarUint(this.filesTransfer.length); + + for (const fileTrans of this.filesTransfer) { + str += hex2VarBytes(fileTrans.serializeHex()); + } + + return str; + } +} diff --git a/src/fs/fsResult.ts b/src/fs/fsResult.ts new file mode 100644 index 00000000..a21ec3ad --- /dev/null +++ b/src/fs/fsResult.ts @@ -0,0 +1,20 @@ +import { hex2VarBytes, StringReader } from '../utils'; +import { decodeBool, decodeVarBytes, serializeBool } from './utils'; + +export class FsResult { + static deserializeHex(hex: string): FsResult { + const sr: StringReader = new StringReader(hex); + const success = decodeBool(sr); + const data = decodeVarBytes(sr); + return new FsResult(success, data); + } + public constructor( + public readonly success: boolean, + public readonly data: string + ) { + + } + public serializeHex(): string { + return serializeBool(this.success) + hex2VarBytes(this.data); + } +} diff --git a/src/fs/getReadPledge.ts b/src/fs/getReadPledge.ts new file mode 100644 index 00000000..b3708545 --- /dev/null +++ b/src/fs/getReadPledge.ts @@ -0,0 +1,23 @@ +import { Address } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { serializeAddress } from './utils'; +import { decodeAddress, decodeVarBytes } from './utils'; + +export class GetReadPledge { + + static deserializeHex(hex: string): GetReadPledge { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + const downloader = decodeAddress(sr); + return new GetReadPledge(fileHash, downloader); + } + public constructor( + public readonly fileHash: string, + public readonly downloader: Address + ) { } + + public serializeHex(): string { + return hex2VarBytes(this.fileHash) + + serializeAddress(this.downloader); + } +} diff --git a/src/fs/index.ts b/src/fs/index.ts new file mode 100644 index 00000000..22457bbc --- /dev/null +++ b/src/fs/index.ts @@ -0,0 +1,17 @@ +export * from './challenge'; +export * from './fileDel'; +export * from './fileHash'; +export * from './fileInfo'; +export * from './filePdpData'; +export * from './fileReadSettleSlice'; +export * from './fileRenew'; +export * from './fileTransfer'; +export * from './fsResult'; +export * from './getReadPledge'; +export * from './nodeInfo'; +export * from './passport'; +export * from './pdpRecord'; +export * from './readPlan'; +export * from './readPledge'; +export * from './space'; +export * from './type'; diff --git a/src/fs/nodeInfo.ts b/src/fs/nodeInfo.ts new file mode 100644 index 00000000..0fe550b3 --- /dev/null +++ b/src/fs/nodeInfo.ts @@ -0,0 +1,86 @@ +import { Address } from '../crypto'; +import { hexstr2str, num2VarInt, str2VarBytes, StringReader } from '../utils'; +import { dateToUnixTime, decodeAddress, decodeVarBytes, decodeVarUint, + serializeUint64, serializeVarUint, unixTimeToDate } from './utils'; + +export class FsNodeInfo { + static deserializeHex(hex: string): FsNodeInfo { + const sr: StringReader = new StringReader(hex); + const pledge = decodeVarUint(sr); + const profit = decodeVarUint(sr); + const volume = decodeVarUint(sr); + const restVol = decodeVarUint(sr); + const serviceTime = unixTimeToDate(decodeVarUint(sr)); + const nodeAddr = decodeAddress(sr); + const nodeNetAddr = hexstr2str(decodeVarBytes(sr)); + return new FsNodeInfo(pledge, profit, volume, restVol, serviceTime, + nodeAddr, nodeNetAddr); + } + public constructor( + public readonly pledge: number, + public readonly profit: number, + public readonly volume: number, + public readonly restVol: number, + public readonly serviceTime: Date, + public readonly nodeAddr: Address, + public readonly nodeNetAddr: string + ) { } + + public serializeHex(): string { + let str = ''; + str += serializeUint64(this.pledge) + + serializeUint64(this.profit) + + serializeUint64(this.volume) + + serializeUint64(this.restVol) + + serializeUint64(dateToUnixTime(this.serviceTime)) + + this.nodeAddr.serialize() + + str2VarBytes(this.nodeNetAddr); + return str; + } + + public export() { + return { + pledge: this.pledge, + profit: this.profit, + volume: this.volume, + restVol: this.restVol, + serviceTime: this.serviceTime, + nodeAddr: this.nodeAddr.value, + nodeNetAddr: this.nodeNetAddr + }; + } +} + +export class FsNodeInfoList { + + static deserializeHex(hex: string): FsNodeInfoList { + const nodeInfos: FsNodeInfo[] = []; + const sr: StringReader = new StringReader(hex); + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const nodeInfo = FsNodeInfo.deserializeHex(sr.readNextBytes()); + nodeInfos.push(nodeInfo); + } + const list = new FsNodeInfoList(nodeInfos); + return list; + } + constructor( + public readonly nodesInfo: FsNodeInfo[] + ) { } + + public serializeHex(): string { + let str = serializeVarUint(this.nodesInfo.length); + for (const nodeInfo of this.nodesInfo) { + const nodeInfoHex = nodeInfo.serializeHex(); + const hexLen = num2VarInt(nodeInfoHex.length / 2); + str += hexLen + nodeInfoHex; + } + return str; + } + + public export() { + return { + nodesInfo: this.nodesInfo.map((info) => info.export()) + }; + } +} diff --git a/src/fs/passport.ts b/src/fs/passport.ts new file mode 100644 index 00000000..f3919202 --- /dev/null +++ b/src/fs/passport.ts @@ -0,0 +1,47 @@ +import { Address, PrivateKey, PublicKey, Signature } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { serializeAddress, serializeVarUint } from './utils'; +import { decodeAddress, decodeVarBytes, decodeVarUint } from './utils'; + +export class Passport { + + static genPassport( + height: number, + blockHash: string, + privateKey: PrivateKey + ): Passport { + const publicKey = privateKey.getPublicKey(); + const walletAddr = Address.fromPubKey(publicKey); + const passport = new Passport(height, blockHash, walletAddr, publicKey); + const signData = privateKey.sign(passport.serializeHex()); + passport.signature = signData; + return passport; + } + static deserializeHex(hex: string): Passport { + const sr: StringReader = new StringReader(hex); + const blockHeight = decodeVarUint(sr); + const blockHash = decodeVarBytes(sr); + const walletAddr = decodeAddress(sr); + const pubKeyHex = decodeVarBytes(sr); + const sigHex = decodeVarBytes(sr); + const sig = Signature.deserializeHex(sigHex); + const pubKey = PublicKey.deserializeHex(new StringReader(pubKeyHex)); + return new Passport(blockHeight, blockHash, walletAddr, pubKey, sig); + } + + public constructor( + public readonly blockHeight: number, + public readonly blockHash: string, + public readonly walletAddr: Address, + public readonly publicKey: PublicKey, + public signature?: Signature + ) { } + + public serializeHex() { + return serializeVarUint(this.blockHeight) + + hex2VarBytes(this.blockHash) + + serializeAddress(this.walletAddr) + + hex2VarBytes(this.publicKey.serializeHex()) + + (this.signature ? hex2VarBytes(this.signature.value) : '00'); + } +} diff --git a/src/fs/pdpRecord.ts b/src/fs/pdpRecord.ts new file mode 100644 index 00000000..4b3482a5 --- /dev/null +++ b/src/fs/pdpRecord.ts @@ -0,0 +1,75 @@ +import { Address } from '../crypto'; +import { bool2VarByte, hex2VarBytes, StringReader } from '../utils'; +import { dateToUnixTime, decodeAddress, decodeBool, decodeVarBytes, + decodeVarUint, serializeAddress, serializeVarUint, unixTimeToDate } from './utils'; + +export class PdpRecord { + + static deserializeHex(hex: string): PdpRecord { + const sr: StringReader = new StringReader(hex); + const nodeAddr = decodeAddress(sr); + const fileHash = decodeVarBytes(sr); + const fileOwner = decodeAddress(sr); + const lastPdpTime = unixTimeToDate(decodeVarUint(sr)); + const settleFlag = decodeBool(sr); + + return new PdpRecord(nodeAddr, fileHash, fileOwner, lastPdpTime, settleFlag); + } + public constructor( + public readonly nodeAddr: Address, + public readonly fileHash: string, + public readonly fileOwner: Address, + public readonly lastPdpTime: Date, + public readonly settleFlag: boolean + ) { } + + public serializeHex(): string { + let str = ''; + str += serializeAddress(this.nodeAddr) + + hex2VarBytes(this.fileHash) + + serializeAddress(this.fileOwner) + + serializeVarUint(dateToUnixTime(this.lastPdpTime)) + + bool2VarByte(this.settleFlag); + return str; + } + + public export() { + return { + nodeAddr: this.nodeAddr.value, + fileHash: this.fileHash, + fileOwner: this.fileOwner.value, + lastPdpTime: this.lastPdpTime, + settleFlag: this.settleFlag + }; + } +} + +export class PdpRecordList { + static deserializeHex(hex: string): PdpRecordList { + const sr: StringReader = new StringReader(hex); + const pdpRecords: PdpRecord[] = []; + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const record = PdpRecord.deserializeHex(decodeVarBytes(sr)); + pdpRecords.push(record); + } + return new PdpRecordList(pdpRecords); + } + public constructor( + public readonly pdpRecords: PdpRecord[] = [] + ) { } + + public serializeHex(): string { + let str = serializeVarUint(this.pdpRecords.length); + for (const pdpRecord of this.pdpRecords) { + str += hex2VarBytes(pdpRecord.serializeHex()); + } + return str; + } + + public export() { + return { + pdpRecords: this.pdpRecords.map((record) => record.export()) + }; + } +} diff --git a/src/fs/readPlan.ts b/src/fs/readPlan.ts new file mode 100644 index 00000000..62ea3725 --- /dev/null +++ b/src/fs/readPlan.ts @@ -0,0 +1,48 @@ +import { Address } from '../crypto'; +import { StringReader } from '../utils'; +import { decodeAddress, decodeVarUint, serializeAddress, serializeVarUint } from './utils'; + +export interface ReadPlanLike { + nodeAddr: Address; + maxReadBlockNum: number; + haveReadBlockNum: number; + numOfSettlements: number; +} + +export class ReadPlan { + static fromReadPlanLike({ nodeAddr, maxReadBlockNum, haveReadBlockNum, numOfSettlements }: ReadPlanLike) { + return new ReadPlan(nodeAddr, maxReadBlockNum, haveReadBlockNum, numOfSettlements); + } + + static deserializeHex(hex: string): ReadPlan { + const sr: StringReader = new StringReader(hex); + const nodeAddr = decodeAddress(sr); + const maxReadBlockNum = decodeVarUint(sr); + const haveReadBlockNum = decodeVarUint(sr); + const numOfSettlements = decodeVarUint(sr); + return new ReadPlan(nodeAddr, maxReadBlockNum, haveReadBlockNum, numOfSettlements); + } + + public constructor( + public readonly nodeAddr: Address, + public readonly maxReadBlockNum: number, + public readonly haveReadBlockNum: number, + public readonly numOfSettlements: number + ) { } + + public serializeHex(): string { + return serializeAddress(this.nodeAddr) + + serializeVarUint(this.maxReadBlockNum) + + serializeVarUint(this.haveReadBlockNum) + + serializeVarUint(this.numOfSettlements); + } + + public export() { + return { + nodeAddr: this.nodeAddr.value, + maxReadBlockNum: this.maxReadBlockNum, + haveReadBlockNum: this.haveReadBlockNum, + numOfSettlements: this.numOfSettlements + }; + } +} diff --git a/src/fs/readPledge.ts b/src/fs/readPledge.ts new file mode 100644 index 00000000..518c1096 --- /dev/null +++ b/src/fs/readPledge.ts @@ -0,0 +1,49 @@ +import { Address } from '../crypto'; +import { hex2VarBytes, StringReader } from '../utils'; +import { ReadPlan } from './readPlan'; +import { decodeAddress, decodeVarBytes, decodeVarUint, serializeAddress, serializeVarUint } from './utils'; + +export class ReadPledge { + static deserializeHex(hex: string): ReadPledge { + const sr: StringReader = new StringReader(hex); + const fileHash = decodeVarBytes(sr); + const downloader = decodeAddress(sr); + const restMoney = decodeVarUint(sr); + const readPlans: ReadPlan[] = []; + const count = decodeVarUint(sr); + for (let i = 0; i < count; i++) { + const plan = ReadPlan.deserializeHex(decodeVarBytes(sr)); + readPlans.push(plan); + } + return new ReadPledge(fileHash, downloader, restMoney, readPlans); + } + public constructor( + public readonly fileHash: string, + public readonly downloader: Address, + public readonly restMoney: number, + public readonly readPlans: ReadPlan[] + ) { } + + public serializeHex(): string { + let str = ''; + str += hex2VarBytes(this.fileHash) + + serializeAddress(this.downloader) + + serializeVarUint(this.restMoney) + + serializeVarUint(this.readPlans.length); + + for (const readPlan of this.readPlans) { + str += hex2VarBytes(readPlan.serializeHex()); + } + + return str; + } + + public export() { + return { + fileHash: this.fileHash, + downloader: this.downloader.value, + restMoney: this.restMoney, + readPlans: this.readPlans.map((plan) => plan.export()) + }; + } +} diff --git a/src/fs/space.ts b/src/fs/space.ts new file mode 100644 index 00000000..f4a9abdd --- /dev/null +++ b/src/fs/space.ts @@ -0,0 +1,88 @@ +import { Address } from '../crypto'; +import { bool2VarByte, StringReader } from '../utils'; +import { dateToUnixTime, decodeAddress, decodeBool, decodeVarUint, + serializeAddress, serializeVarUint, unixTimeToDate } from './utils'; + +export class SpaceInfo { + + static deserializeHex(hex: string): SpaceInfo { + const sr: StringReader = new StringReader(hex); + const spaceOwner = decodeAddress(sr); + const volume = decodeVarUint(sr); + const restVol = decodeVarUint(sr); + const copyNumber = decodeVarUint(sr); + const payAmount = decodeVarUint(sr); + const restAmount = decodeVarUint(sr); + const timeStart = unixTimeToDate(decodeVarUint(sr)); + const timeExpired = unixTimeToDate(decodeVarUint(sr)); + const currFeeRate = decodeVarUint(sr) + const validFlag = decodeBool(sr); + return new SpaceInfo(spaceOwner, volume, restVol, copyNumber, payAmount, + restAmount, timeStart, timeExpired, currFeeRate, validFlag); + } + public constructor( + public readonly spaceOwner: Address, + public readonly volume: number, + public readonly restVol: number, + public readonly copyNumber: number, + public readonly payAmount: number, + public readonly restAmount: number, + public readonly timeStart: Date, + public readonly timeExpired: Date, + public readonly currFeeRate: number, + public readonly validFlag: boolean + ) { } + + public serializeHex(): string { + return serializeAddress(this.spaceOwner) + + serializeVarUint(this.volume) + + serializeVarUint(this.restVol) + + serializeVarUint(this.copyNumber) + + serializeVarUint(this.payAmount) + + serializeVarUint(this.restAmount) + + serializeVarUint(dateToUnixTime(this.timeStart)) + + serializeVarUint(dateToUnixTime(this.timeExpired)) + + serializeVarUint(this.currFeeRate) + + bool2VarByte(this.validFlag); + } + + public export() { + return { + spaceOwner: this.spaceOwner.value, + volume: this.volume, + restVol: this.restVol, + copyNumber: this.copyNumber, + payAmount: this.payAmount, + restAmount: this.restAmount, + timeStart: this.timeStart, + timeExpired: this.timeExpired, + currFeeRate: this.currFeeRate, + validFlag: this.validFlag + }; + } +} + +export class SpaceUpdate { + static deserializeHex(hex: string): SpaceUpdate { + const sr: StringReader = new StringReader(hex); + const spaceOwner = decodeAddress(sr); + const payer = decodeAddress(sr); + const newVolume = decodeVarUint(sr); + const newTimeExpired = unixTimeToDate(decodeVarUint(sr)); + + return new SpaceUpdate(spaceOwner, payer, newVolume, newTimeExpired); + } + public constructor( + public readonly spaceOwner: Address, + public readonly payer: Address, + public readonly newVolume: number, + public readonly newTimeExpired: Date + ) { } + + public serializeHex(): string { + return serializeAddress(this.spaceOwner) + + serializeAddress(this.payer) + + serializeVarUint(this.newVolume) + + serializeVarUint(dateToUnixTime(this.newTimeExpired)); + } +} diff --git a/src/fs/type.ts b/src/fs/type.ts new file mode 100644 index 00000000..7e3e5223 --- /dev/null +++ b/src/fs/type.ts @@ -0,0 +1,24 @@ +import { Address } from '../crypto'; + +export interface FileStore { + fileHash: string; + fileDesc: string; + fileBlockCount: number; + realFileSize: number; + copyNumber: number; + firstPdp: boolean; + timeStart: Date; + timeExpired: Date; + pdpParam: string; + storageType: number; +} + +export interface FileRenewInterface { + fileHash: string; + renewTime: Date; +} + +export interface FileTransferInterface { + fileHash: string; + newOwner: Address; +} diff --git a/src/fs/utils.ts b/src/fs/utils.ts new file mode 100644 index 00000000..87053d32 --- /dev/null +++ b/src/fs/utils.ts @@ -0,0 +1,72 @@ +import { Address } from '../crypto/address'; +import { hex2VarBytes, num2hexstring, reverseHex, StringReader } from '../utils'; +export function serializeUint64(num: number): string { + return hex2VarBytes(num2hexstring(num, 8)); +} + +export function serializeVarUint(num: number): string { + let hex = ''; + if (num < 0x80) { + hex = num2hexstring(num); + } else if (num < 0x8000) { + hex = num2hexstring(num, 2, true); + } else if (num < 0x800000) { + hex = num2hexstring(num, 3, true); + } else if (num < 0x80000000) { + hex = num2hexstring(num, 4, true); + } else if (num < 0x8000000000) { + hex = num2hexstring(num, 5, true); + } else if (num < 0x800000000000) { + hex = num2hexstring(num, 6, true); + } else if (num < 0x80000000000000) { + hex = num2hexstring(num, 7, true); + } else { + hex = num2hexstring(num, 8, true); + } + if (hex === '00') { + return hex; + } + return hex2VarBytes(hex); +} + +export function serializeAddress(addr: Address): string { + return hex2VarBytes(addr.serialize()); +} + +export function serializeBool(bool: boolean): string { + return bool ? '01' : '00'; +} + +export function decodeBool(sr: StringReader): boolean { + return sr.readBoolean(); +} + +export function decodeVarBytes(sr: StringReader): string { + return sr.readNextBytes(); +} + +export function decodeVarUint(sr: StringReader): number { + const nextBytes = sr.readNextBytes(); + if (nextBytes === '') { + return 0; + } + const hex = reverseHex(nextBytes); + return parseInt(hex, 16); +} + +export function decodeAddress(sr: StringReader): Address { + const nextBytes = sr.readNextBytes(); + if (nextBytes === '') { + return new Address(''); + } + const addr = new Address(nextBytes); + return addr; +} + +export function dateToUnixTime(date: Date): number { + return Math.floor(date.getTime() / 1000); +} + +export function unixTimeToDate(unixTime: number): Date { + return new Date(unixTime * 1000); +} diff --git a/src/index.ts b/src/index.ts index 8a96650b..d71b7415 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,7 @@ import { Account } from './account'; import { Claim } from './claim'; import * as CONST from './consts'; import * as Crypto from './crypto'; +import * as FS from './fs'; import { Identity } from './identity'; import * as NeoCore from './neocore'; import RestClient from './network/rest/restClient'; @@ -33,6 +34,7 @@ import { Parameter, ParameterType } from './smartcontract/abi/parameter'; import Struct from './smartcontract/abi/struct'; import * as GovernanceTxBuilder from './smartcontract/nativevm/governanceContractTxBuilder'; import * as OntAssetTxBuilder from './smartcontract/nativevm/ontAssetTxBuilder'; +import * as OntfsContractTxBuilder from './smartcontract/nativevm/ontfsContractTxBuilder'; import * as OntidContract from './smartcontract/nativevm/ontidContractTxBuilder'; import * as Token from './smartcontract/nativevm/token'; import * as Oep4 from './smartcontract/neovm/oep4TxBuilder'; @@ -53,11 +55,13 @@ class ONT { Claim: any; DDO: any; DDOAttribute: any; + FS: any; Transaction: any; Transfer: any; TxSignature: any; TransactionBuilder: any; OntAssetTxBuilder: any; + OntfsContractTxBuilder: any; Parameter: any; ParameterType: any; AbiFunction: any; @@ -87,12 +91,14 @@ class ONT { this.Claim = Claim; this.DDO = DDO; this.DDOAttribute = DDOAttribute; + this.FS = FS; this.Transaction = Transaction; this.Transfer = Transfer; this.TxSignature = TxSignature; this.TransactionBuilder = TransactionBuilder; this.OntAssetTxBuilder = OntAssetTxBuilder; this.GovernanceTxBuilder = GovernanceTxBuilder; + this.OntfsContractTxBuilder = OntfsContractTxBuilder; this.Parameter = Parameter; this.ParameterType = ParameterType; this.AbiFunction = AbiFunction; @@ -140,6 +146,7 @@ export { Claim, DDO, DDOAttribute, + FS, Transaction, Transfer, TxSignature, @@ -150,6 +157,7 @@ export { TransactionBuilder, OntAssetTxBuilder, GovernanceTxBuilder, + OntfsContractTxBuilder, utils, scrypt, CONST, diff --git a/src/smartcontract/nativevm/ontfsContractTxBuilder.ts b/src/smartcontract/nativevm/ontfsContractTxBuilder.ts new file mode 100644 index 00000000..98c8e850 --- /dev/null +++ b/src/smartcontract/nativevm/ontfsContractTxBuilder.ts @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +import BigNumber from 'bignumber.js'; +import { Address, PrivateKey, PublicKey, Signature } from '../../crypto'; +import { + Challenge, FileDel, FileDelList, FileInfo, FileInfoList, FilePdpData, + FileReadSettleSlice, FileRenew, FileRenewInterface, FileRenewList, + FileStore, FileTransfer, FileTransferInterface, FileTransferList, + FsNodeInfo, GetReadPledge, Passport, ReadPlan, ReadPlanLike, + ReadPledge, SpaceInfo, SpaceUpdate +} from '../../fs'; +import { Transaction } from '../../transaction/transaction'; +import { makeNativeContractTx } from '../../transaction/transactionUtils'; +import { str2hexstr, StringReader } from '../../utils'; +import { buildNativeCodeScript } from '../abi/nativeVmParamsBuilder'; +import Struct from '../abi/struct'; + +/** + * Address of ONT FS Contract + */ +export const ONTFS_CONTRACT = '0000000000000000000000000000000000000008'; +const contractAddress = new Address(ONTFS_CONTRACT); + +/** + * Method names in ONT FS contract + */ +export const ONTFS_METHOD = { + FsGetGlobalParam: 'FsGetGlobalParam', + FsNodeRegister: 'FsNodeRegister', + FsNodeQuery: 'FsNodeQuery', + FsNodeUpdate: 'FsNodeUpdate', + FsNodeCancel: 'FsNodeCancel', + FsFileProve: 'FsFileProve', + FsNodeWithDrawProfit: 'FsNodeWithDrawProfit', + FsGetNodeList: 'FsGetNodeList', + FsGetPdpInfoList: 'FsGetPdpInfoList', + FsChallenge: 'FsChallenge', + FsResponse: 'FsResponse', + FsJudge: 'FsJudge', + FsGetChallenge: 'FsGetChallenge', + FsGetFileChallengeList: 'FsGetFileChallengeList', + FsGetNodeChallengeList: 'FsGetNodeChallengeList', + FsStoreFiles: 'FsStoreFiles', + FsRenewFiles: 'FsRenewFiles', + FsDeleteFiles: 'FsDeleteFiles', + FsTransferFiles: 'FsTransferFiles', + FsGetFileInfo: 'FsGetFileInfo', + FsGetFileList: 'FsGetFileList', + FsReadFilePledge: 'FsReadFilePledge', + FsReadFileSettle: 'FsReadFileSettle', + FsGetReadPledge: 'FsGetReadPledge', + FsCancelFileRead: 'FsCancelFileRead', + FsSetWhiteList: 'FsSetWhiteList', + FsGetWhiteList: 'FsGetWhiteList', + FsCreateSpace: 'FsCreateSpace', + FsDeleteSpace: 'FsDeleteSpace', + FsUpdateSpace: 'FsUpdateSpace', + FsGetSpaceInfo: 'FsGetSpaceInfo' +}; + +export function buildTxByParamsHash( + method: keyof typeof ONTFS_METHOD, + paramsHash: string, + gasPrice: string, + gasLimit: string, + payer?: Address +) { + return makeNativeContractTx(method, paramsHash, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildGetGlobalParamTx(): Transaction { + return makeNativeContractTx(ONTFS_METHOD.FsGetGlobalParam, '', contractAddress); +} + +export function buildFsNodeRegisterTx( + volume: number, + serviceTime: Date, + nodeAddr: Address, + nodeNetAddr: string, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const fsNodeInfo = new FsNodeInfo(0, 0, volume, 0, serviceTime, nodeAddr, nodeNetAddr); + const struct = new Struct(); + struct.add(fsNodeInfo.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsNodeRegister, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildNodeQueryTx( + nodeAddr: Address +): Transaction { + const struct = new Struct(); + struct.add(nodeAddr.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsNodeQuery, params, contractAddress); +} + +export function buildNodeUpdateTx( + volume: number, + serviceTime: Date, + nodeAddr: Address, + nodeNetAddr: string, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const fsNodeInfo = new FsNodeInfo(0, 0, volume, 0, serviceTime, nodeAddr, nodeNetAddr); + const struct = new Struct(); + struct.add(fsNodeInfo.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsNodeUpdate, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildNodeCancelTx( + nodeAddr: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const struct = new Struct(); + struct.add(nodeAddr.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsNodeCancel, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildNodeWithdrawoProfitTx( + nodeAddr: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const struct = new Struct(); + struct.add(nodeAddr.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsNodeWithDrawProfit, params, contractAddress, gasPrice, gasLimit, payer); +} + +/** + * + * @param nodeAddr + * @param fileHash hex string + * @param proveData hex string + * @param blockHeight + * @param gasPrice + * @param gasLimit + * @param payer + */ +export function buildFileProveTx( + nodeAddr: Address, + fileHash: string, + proveData: string, + blockHeight: number, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const pdpData = new FilePdpData(nodeAddr, fileHash, proveData, blockHeight); + const struct = new Struct(); + struct.add(pdpData.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsFileProve, params, contractAddress, gasPrice, gasLimit, payer); +} + +/** + * + * @param fileHash hex string + * @param downloader + */ +export function buildGetFileReadPledgeTx( + fileHash: string, + downloader: Address +): Transaction { + const getReadPledge = new GetReadPledge(fileHash, downloader); + const struct = new Struct(); + struct.add(getReadPledge.fileHash); + struct.add(getReadPledge.downloader.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetReadPledge, params, contractAddress); +} + +export function buildFileReadProfitSettleTx( + fileReadSettleSlice: FileReadSettleSlice, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const struct = new Struct(); + struct.add(fileReadSettleSlice.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsReadFileSettle, params, contractAddress, gasPrice, gasLimit, payer); +} + +/** + * + * @param fileHash hex + */ +export function buildGetFilePdpRecordListTx( + fileHash: string +): Transaction { + const struct = new Struct(); + struct.add(fileHash); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetPdpInfoList, params, contractAddress); +} + +// export function buildGetNodeInfoTx( +// nodeAddr: Address +// ): Transaction {} + +export function buildGetNodeInfoListTx( + count: number +): Transaction { + const struct = new Struct(); + struct.add(new BigNumber(count)); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetNodeList, params, contractAddress); +} + +export function buildChallengeTx( + fileHash: string, + fileOwner: Address, + nodeAddr: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const chanllege = new Challenge(fileHash, fileOwner, nodeAddr); + const struct = new Struct(); + struct.add(chanllege.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsChallenge, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildGetChanllengeTx( + fileHash: string, + fileOwner: Address, + nodeAddr: Address +): Transaction { + const challengeReq = new Challenge(fileHash, fileOwner, nodeAddr); + const struct = new Struct(); + struct.add(challengeReq.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetChallenge, params, contractAddress); +} + +export function buildResponseTx( + nodeAddr: Address, + fileHash: string, + proveData: string, + blockHeight: number, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const pdpData = new FilePdpData(nodeAddr, fileHash, proveData, blockHeight); + const struct = new Struct(); + struct.add(pdpData.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsResponse, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildJudgeTx( + fileHash: string, + fileOwner: Address, + nodeAddr: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const challenge = new Challenge(fileHash, fileOwner, nodeAddr); + const struct = new Struct(); + struct.add(challenge.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsJudge, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildGetFileChallengeListTx( + fileHash: string, + fileOwner: Address +): Transaction { + const challengeReq = new Challenge(fileHash, fileOwner); + const struct = new Struct(); + struct.add(challengeReq.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetFileChallengeList, params, contractAddress); +} + +export function buildGetNodeChallengeListTx( + fileOwner: Address +): Transaction { + const struct = new Struct(); + struct.add(fileOwner.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetNodeChallengeList, params, contractAddress); +} + +export function buildCreateSpaceTx( + spaceOwner: Address, + volume: number, + copyNum: number, + timeStart: Date, + timeExpired: Date, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const spaceInfo = new SpaceInfo(spaceOwner, volume, 0, copyNum, 0, 0, timeStart, timeExpired, 0, false); + const struct = new Struct(); + struct.add(spaceInfo.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsCreateSpace, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildGetSpaceInfoTx( + spaceOwner: Address +): Transaction { + const struct = new Struct(); + struct.add(spaceOwner.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetSpaceInfo, params, contractAddress); +} + +export function buildUpdateSpaceTx( + spaceOwner: Address, + spacePayer: Address, + volume: number, + timeExpired: Date, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const spaceUdpate = new SpaceUpdate(spaceOwner, spacePayer, volume, timeExpired); + const struct = new Struct(); + struct.add(spaceUdpate.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsUpdateSpace, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildDeleteSpaceTx( + spaceOwner: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const struct = new Struct(); + struct.add(spaceOwner.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsDeleteSpace, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function genPassport( + blockHeight: number, + blockHash: string, + privateKey: PrivateKey +): Passport { + return Passport.genPassport(blockHeight, blockHash, privateKey); +} + +export function genFileReadSettleSlice( + fileHash: string, + payTo: Address, + sliceId: number, + pledgeHeight: number, + privateKey: PrivateKey +): FileReadSettleSlice { + return FileReadSettleSlice.genFileReadSettleSlice( + fileHash, payTo, sliceId, pledgeHeight, privateKey + ); +} + +export function verifyFileReadSettleSlice( + { + fileHash, payFrom, payTo, sliceId, pledgeHeight, signature, publicKey + }: { + fileHash: string; + payFrom: string; + payTo: string; + sliceId: number; + pledgeHeight: number; + signature: string; + publicKey: string; + } +): boolean { + const settleSlice = new FileReadSettleSlice( + fileHash, new Address(payFrom), new Address(payTo), sliceId, pledgeHeight, + Signature.deserializeHex(signature), PublicKey.deserializeHex(new StringReader(publicKey)) + ); + return settleSlice.verify(); +} + +export function buildGetFileListTx( + passport: Passport | string +): Transaction { + const struct = new Struct(); + struct.add(typeof passport === 'string' ? passport : passport.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetFileList, params, contractAddress); +} + +export function buildGetFileInfoTx( + fileHash: string +): Transaction { + const struct = new Struct(); + struct.add(fileHash); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsGetFileInfo, params, contractAddress); +} + +export function buildStoreFilesTx( + filesInfo: FileStore[], + fileOwner: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const fileInfoList = new FileInfoList(); + for ( + const { + fileHash, + fileDesc, + fileBlockCount, + realFileSize, + copyNumber, + firstPdp, + timeStart, + timeExpired, + pdpParam, + storageType + } of filesInfo + ) { + const fsFileInfo = new FileInfo( + fileHash, fileOwner, str2hexstr(fileDesc), fileBlockCount, realFileSize, copyNumber, + 0, 0, firstPdp, new Date(timeStart), new Date(timeExpired), 0, 0, pdpParam, false, 0, storageType); + fileInfoList.filesI.push(fsFileInfo); + } + + const struct = new Struct(); + struct.add(fileInfoList.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsStoreFiles, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildTransferFilesTx( + fileTransfers: FileTransferInterface[], + originOwner: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const fileTransferList = new FileTransferList(); + for (const { fileHash, newOwner } of fileTransfers) { + const fsFileTransfer = new FileTransfer(fileHash, originOwner, newOwner); + fileTransferList.filesTransfer.push(fsFileTransfer); + } + const struct = new Struct(); + struct.add(fileTransferList.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsTransferFiles, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildRenewFilesTx( + filesRenew: FileRenewInterface[], + newFileOwner: Address, + newPayer: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const fileRenewList = new FileRenewList(); + for (const { fileHash, renewTime } of filesRenew) { + const fsFileRenew = new FileRenew(fileHash, newFileOwner, newPayer, renewTime); + fileRenewList.filesRenew.push(fsFileRenew); + } + const struct = new Struct(); + struct.add(fileRenewList.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsRenewFiles, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildDeleteFilesTx( + fileHashes: string[], + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const fileDelList = new FileDelList(); + for (const fileHash of fileHashes) { + fileDelList.filesDel.push( + new FileDel(fileHash) + ); + } + const struct = new Struct(); + struct.add(fileDelList.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsDeleteFiles, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildFileReadPledgeTx( + fileHash: string, + readPlans: ReadPlanLike[], + downloader: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const fileReadPledge = new ReadPledge(fileHash, downloader, 0, + readPlans.map((plan) => ReadPlan.fromReadPlanLike(plan))); + const struct = new Struct(); + struct.add(fileReadPledge.serializeHex()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsReadFilePledge, params, contractAddress, gasPrice, gasLimit, payer); +} + +export function buildCancelFileReadTx( + fileHash: string, + downloader: Address, + gasPrice: string, + gasLimit: string, + payer?: Address +): Transaction { + const getReadPledge = new GetReadPledge(fileHash, downloader); + const struct = new Struct(); + struct.add(getReadPledge.fileHash); + struct.add(getReadPledge.downloader.serialize()); + const params = buildNativeCodeScript([struct]); + return makeNativeContractTx(ONTFS_METHOD.FsCancelFileRead, params, contractAddress, gasPrice, gasLimit, payer); +}