diff --git a/e2e/e2e-preset.yml b/e2e/e2e-preset.yml index 80f38803d2..f68b596f1c 100644 --- a/e2e/e2e-preset.yml +++ b/e2e/e2e-preset.yml @@ -1,4 +1,4 @@ nemesis: mosaics: - accounts: 10 -symbolRestImage: symbolplatform/symbol-rest:2.1.1-alpha +symbolRestImage: symbolplatform/symbol-rest:2.1.1-alpha-202011061935 diff --git a/e2e/infrastructure/IntegrationTestHelper.ts b/e2e/infrastructure/IntegrationTestHelper.ts index ec7f58609c..f59c546be1 100644 --- a/e2e/infrastructure/IntegrationTestHelper.ts +++ b/e2e/infrastructure/IntegrationTestHelper.ts @@ -48,8 +48,9 @@ export class IntegrationTestHelper { public config: StartParams; public startEachTime = true; public epochAdjustment: number; + public bootstrapAddresses: Addresses; - private async startBootstrapServer(): Promise<{ accounts: string[]; apiUrl: string }> { + private async startBootstrapServer(): Promise<{ accounts: string[]; apiUrl: string; addresses: Addresses }> { this.config = { report: false, preset: Preset.bootstrap, @@ -65,7 +66,7 @@ export class IntegrationTestHelper { const configResult = await this.service.start({ ...this.config, detached: true }); return this.toAccounts(configResult.addresses); } - private async loadBootstrap(): Promise<{ accounts: string[]; apiUrl: string }> { + private async loadBootstrap(): Promise<{ accounts: string[]; apiUrl: string; addresses: Addresses }> { // const target = '../catapult-rest/rest/target'; const target = 'target/bootstrap-test'; console.log('Loading bootstrap server'); @@ -73,12 +74,12 @@ export class IntegrationTestHelper { return this.toAccounts(addresses); } - private toAccounts(addresses: Addresses): { accounts: string[]; apiUrl: string } { + private toAccounts(addresses: Addresses): { accounts: string[]; apiUrl: string; addresses: Addresses } { const accounts = addresses?.mosaics?.[0].accounts.map((n) => n.privateKey); if (!accounts) { throw new Error('Nemesis accounts could not be loaded!'); } - return { accounts, apiUrl: 'http://localhost:3000' }; + return { accounts, apiUrl: 'http://localhost:3000', addresses }; } async close(): Promise { @@ -94,6 +95,7 @@ export class IntegrationTestHelper { // await this.service.stop(this.config); const config = await this.loadBootstrap(); const accounts = config.accounts; + this.bootstrapAddresses = config.addresses; this.apiUrl = config.apiUrl; this.repositoryFactory = new RepositoryFactoryHttp(this.apiUrl); this.transactionService = new TransactionService( diff --git a/e2e/infrastructure/PersistentHarvesting.spec.ts b/e2e/infrastructure/PersistentHarvesting.spec.ts index 9c87693381..eaaf03e0ff 100644 --- a/e2e/infrastructure/PersistentHarvesting.spec.ts +++ b/e2e/infrastructure/PersistentHarvesting.spec.ts @@ -14,14 +14,16 @@ * limitations under the License. */ -import { Account } from '../../src/model/account/Account'; -import { NetworkType } from '../../src/model/network/NetworkType'; -import { AccountKeyLinkTransaction } from '../../src/model/transaction/AccountKeyLinkTransaction'; -import { Deadline } from '../../src/model/transaction/Deadline'; -import { LinkAction } from '../../src/model/transaction/LinkAction'; -import { NodeKeyLinkTransaction } from '../../src/model/transaction/NodeKeyLinkTransaction'; -import { PersistentDelegationRequestTransaction } from '../../src/model/transaction/PersistentDelegationRequestTransaction'; -import { VrfKeyLinkTransaction } from '../../src/model/transaction/VrfKeyLinkTransaction'; +import { Account } from '../../src/model/account'; +import { NetworkType } from '../../src/model/network'; +import { + AccountKeyLinkTransaction, + Deadline, + LinkAction, + NodeKeyLinkTransaction, + PersistentDelegationRequestTransaction, + VrfKeyLinkTransaction, +} from '../../src/model/transaction'; import { IntegrationTestHelper } from './IntegrationTestHelper'; describe('PersistentHarvesting', () => { @@ -29,20 +31,21 @@ describe('PersistentHarvesting', () => { let account: Account; let generationHash: string; let networkType: NetworkType; + let vrfAccount: Account; let remoteAccount: Account; - - const vrfKeyPair = Account.createFromPrivateKey( - '82798EA9A2D2D202AFCCC82C40A287780BCA3C7F7A2FD5B754832804C6BE1BAA', - NetworkType.PRIVATE_TEST, - ); + let nodePublicKey: string; before(() => { return helper.start({ openListener: true }).then(() => { - remoteAccount = Account.generateNewAccount(helper.networkType); - console.log(remoteAccount.privateKey, remoteAccount.publicAccount); - account = helper.harvestingAccount; - generationHash = helper.generationHash; networkType = helper.networkType; + remoteAccount = Account.createFromPrivateKey('CC798EA9A2D2D202AFCCC82C40A287780BCA3C7F7A2FD5B754832804C6BE1BAA', networkType); + vrfAccount = Account.createFromPrivateKey('AA798EA9A2D2D202AFCCC82C40A287780BCA3C7F7A2FD5B754832804C6BE1BAA', networkType); + account = helper.account; + generationHash = helper.generationHash; + nodePublicKey = helper.bootstrapAddresses.nodes![0].signing!.publicKey; + console.log('Remote: ', remoteAccount.publicAccount); + console.log('VRF: ', vrfAccount.publicAccount); + console.log('Node Public Key: ', nodePublicKey); }); }); @@ -57,7 +60,16 @@ describe('PersistentHarvesting', () => { */ describe('AccountKeyLinkTransaction', () => { - it('standalone', () => { + it('standalone', async () => { + const accountInfo = await helper.repositoryFactory.createAccountRepository().getAccountInfo(account.address).toPromise(); + const publicKey = accountInfo.supplementalPublicKeys?.linked?.publicKey; + if (publicKey) { + if (publicKey == remoteAccount.publicKey) { + return; + } + throw new Error(`Account ${accountInfo.address.plain()} already linked to another Remote public key ${publicKey}`); + } + const accountLinkTransaction = AccountKeyLinkTransaction.create( Deadline.create(helper.epochAdjustment), remoteAccount.publicKey, @@ -72,10 +84,20 @@ describe('PersistentHarvesting', () => { }); describe('VrfKeyLinkTransaction', () => { - it('standalone', () => { + it('standalone', async () => { + const accountInfo = await helper.repositoryFactory.createAccountRepository().getAccountInfo(account.address).toPromise(); + + const publicKey = accountInfo.supplementalPublicKeys?.vrf?.publicKey; + if (publicKey) { + if (publicKey == vrfAccount.publicKey) { + return; + } + throw new Error(`Account ${accountInfo.address.plain()} already linked to another VRF public key ${publicKey}`); + } + const vrfKeyLinkTransaction = VrfKeyLinkTransaction.create( Deadline.create(helper.epochAdjustment), - vrfKeyPair.publicKey, + vrfAccount.publicKey, LinkAction.Link, networkType, helper.maxFee, @@ -87,10 +109,22 @@ describe('PersistentHarvesting', () => { }); describe('NodeKeyLinkTransaction', () => { - it('standalone', () => { + it('standalone', async () => { + const nodePublicKey = helper.bootstrapAddresses.nodes![0].signing!.publicKey; + + const accountInfo = await helper.repositoryFactory.createAccountRepository().getAccountInfo(account.address).toPromise(); + + const publicKey = accountInfo.supplementalPublicKeys?.node?.publicKey; + if (publicKey) { + if (publicKey == nodePublicKey) { + return; + } + throw new Error(`Account ${accountInfo.address.plain()} already linked to another Node public key ${publicKey}`); + } + const nodeKeyLinkTransaction = NodeKeyLinkTransaction.create( Deadline.create(helper.epochAdjustment), - 'cfd84eca83508bbee954668e4aecca736caefa615367da76afe6985d695381db', + nodePublicKey, LinkAction.Link, networkType, helper.maxFee, @@ -107,15 +141,17 @@ describe('PersistentHarvesting', () => { */ describe('transactions', () => { - it('should create delegated harvesting transaction', () => { + it('should create delegated harvesting transaction', async () => { + const nodePublicKey = helper.bootstrapAddresses.nodes![0].signing!.publicKey; const tx = PersistentDelegationRequestTransaction.createPersistentDelegationRequestTransaction( Deadline.create(helper.epochAdjustment), remoteAccount.privateKey, - vrfKeyPair.privateKey, - 'cfd84eca83508bbee954668e4aecca736caefa615367da76afe6985d695381db', - NetworkType.PRIVATE_TEST, + vrfAccount.privateKey, + nodePublicKey, + networkType, helper.maxFee, ); + console.log(tx.message.toDTO()); const signedTransaction = tx.signWith(account, generationHash); return helper.announce(signedTransaction); diff --git a/package-lock.json b/package-lock.json index b62327a21e..a0ccaf84b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6159,7 +6159,7 @@ }, "which-module": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, diff --git a/package.json b/package.json index a3615cb59c..fbff396d08 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "bootstrap-clean": "symbol-bootstrap clean -t target/bootstrap-test", "bootstrap-start-detached": "symbol-bootstrap start -r -c ./e2e/e2e-preset.yml -t target/bootstrap-test --timeout 120000 -d --healthCheck", "bootstrap-start": "symbol-bootstrap start -r -c ./e2e/e2e-preset.yml --timeout 120000 -t target/bootstrap-test", + "bootstrap-upgrade": "symbol-bootstrap compose -r -t target/bootstrap-test", "bootstrap-stop": "symbol-bootstrap stop -t target/bootstrap-test", "bootstrap-run": "symbol-bootstrap run -t target/bootstrap-test", "bootstrap-compose": "symbol-bootstrap compose -t target/bootstrap-test", diff --git a/src/model/message/EncryptedMessage.ts b/src/model/message/EncryptedMessage.ts index 12ac76f67f..5558a7bea8 100644 --- a/src/model/message/EncryptedMessage.ts +++ b/src/model/message/EncryptedMessage.ts @@ -15,7 +15,7 @@ */ import { Crypto } from '../../core/crypto'; -import { PublicAccount } from '../account/PublicAccount'; +import { PublicAccount } from '../account'; import { Message } from './Message'; import { MessageType } from './MessageType'; import { PlainMessage } from './PlainMessage'; @@ -46,7 +46,11 @@ export class EncryptedMessage extends Message { } /** + * It creates a encrypted message from the payload hex wihtout the 01 prefix. * + * The 01 prefix will be attached to the final payload. + * + * @internal * @param payload */ public static createFromPayload(payload: string): EncryptedMessage { diff --git a/src/model/message/MessageFactory.ts b/src/model/message/MessageFactory.ts index 28383cfe58..a7efbbab03 100644 --- a/src/model/message/MessageFactory.ts +++ b/src/model/message/MessageFactory.ts @@ -38,23 +38,27 @@ export class MessageFactory { } /** * It creates a message from the hex payload - * @param payload the payload as byte array + * @param payload the payload as hex */ public static createMessageFromHex(payload?: string): Message { if (!payload || !payload.length) { return new RawMessage(''); } - if (payload.length == 264 && payload.startsWith(MessageMarker.PersistentDelegationUnlock)) { - return new PersistentHarvestingDelegationMessage(payload); + const upperCasePayload = payload.toUpperCase(); + if ( + upperCasePayload.length == PersistentHarvestingDelegationMessage.HEX_PAYLOAD_SIZE && + upperCasePayload.startsWith(MessageMarker.PersistentDelegationUnlock) + ) { + return PersistentHarvestingDelegationMessage.createFromPayload(upperCasePayload); } - const messageType = Convert.hexToUint8(payload)[0]; + const messageType = Convert.hexToUint8(upperCasePayload)[0]; switch (messageType) { case MessageType.PlainMessage: - return new PlainMessage(Message.decodeHex(payload.substring(2))); + return PlainMessage.createFromPayload(upperCasePayload.substring(2)); case MessageType.EncryptedMessage: - return new EncryptedMessage(Message.decodeHex(payload.substring(2))); + return EncryptedMessage.createFromPayload(upperCasePayload.substring(2)); } - return new RawMessage(payload); + return new RawMessage(upperCasePayload); } } diff --git a/src/model/message/MessageMarker.ts b/src/model/message/MessageMarker.ts index 2e8181a1e0..8dc4189a00 100644 --- a/src/model/message/MessageMarker.ts +++ b/src/model/message/MessageMarker.ts @@ -16,7 +16,7 @@ export class MessageMarker { /** - * 8-byte marker: E201735761802AFE for PersistentDelegationRequestTransaction message + * 8-byte marker: FE2A8061577301E2 for PersistentDelegationRequestTransaction message */ - public static readonly PersistentDelegationUnlock = 'E201735761802AFE'; + public static readonly PersistentDelegationUnlock = 'FE2A8061577301E2'; } diff --git a/src/model/message/PersistentHarvestingDelegationMessage.ts b/src/model/message/PersistentHarvestingDelegationMessage.ts index cc542b60d4..18c6740ef9 100644 --- a/src/model/message/PersistentHarvestingDelegationMessage.ts +++ b/src/model/message/PersistentHarvestingDelegationMessage.ts @@ -23,22 +23,34 @@ import { MessageMarker } from './MessageMarker'; import { MessageType } from './MessageType'; export class PersistentHarvestingDelegationMessage extends Message { + public static readonly HEX_PAYLOAD_SIZE = 264; + constructor(payload: string) { - super(MessageType.PersistentHarvestingDelegationMessage, payload); + super(MessageType.PersistentHarvestingDelegationMessage, payload.toUpperCase()); if (!Convert.isHexString(payload)) { throw Error('Payload format is not valid hexadecimal string'); } + if (payload.length != PersistentHarvestingDelegationMessage.HEX_PAYLOAD_SIZE) { + throw Error( + `Invalid persistent harvesting delegate payload size! Expected ${PersistentHarvestingDelegationMessage.HEX_PAYLOAD_SIZE} but got ${payload.length}`, + ); + } + if (payload.toUpperCase().indexOf(MessageMarker.PersistentDelegationUnlock) != 0) { + throw Error( + `Invalid persistent harvesting delegate payload! It does not start with ${MessageMarker.PersistentDelegationUnlock}`, + ); + } } /** - * @param signingPrivateKey - Remote harvester signing private key linked to the main account + * @param remoteLinkedPrivateKey - Remote harvester signing private key linked to the main account * @param vrfPrivateKey - VRF private key linked to the main account * @param nodePublicKey - Node certificate public key * @param {NetworkType} networkType - Catapult network type * @return {PersistentHarvestingDelegationMessage} */ public static create( - signingPrivateKey: string, + remoteLinkedPrivateKey: string, vrfPrivateKey: string, nodePublicKey: string, networkType: NetworkType, @@ -47,17 +59,18 @@ export class PersistentHarvestingDelegationMessage extends Message { const encrypted = MessageMarker.PersistentDelegationUnlock + ephemeralKeypair.publicKey + - Crypto.encode(ephemeralKeypair.privateKey, nodePublicKey, signingPrivateKey + vrfPrivateKey, true).toUpperCase(); + Crypto.encode(ephemeralKeypair.privateKey, nodePublicKey, remoteLinkedPrivateKey + vrfPrivateKey, true).toUpperCase(); return new PersistentHarvestingDelegationMessage(encrypted); } /** - * Create PersistentHarvestingDelegationMessage from DTO payload + * Create PersistentHarvestingDelegationMessage from DTO payload with marker. + * @internal * @param payload + * */ public static createFromPayload(payload: string): PersistentHarvestingDelegationMessage { - const msgTypeHex = MessageType.PersistentHarvestingDelegationMessage.toString(16).toUpperCase(); - return new PersistentHarvestingDelegationMessage(msgTypeHex + payload.toUpperCase()); + return new PersistentHarvestingDelegationMessage(payload); } /** diff --git a/src/model/message/PlainMessage.ts b/src/model/message/PlainMessage.ts index 4a86eb9619..4611b7831f 100644 --- a/src/model/message/PlainMessage.ts +++ b/src/model/message/PlainMessage.ts @@ -30,6 +30,11 @@ export class PlainMessage extends Message { } /** + * + * It creates the Plain message from a payload hex without the 00 prefix. + * + * The 00 prefix will be attached to the final payload. + * * @internal */ public static createFromPayload(payload: string): PlainMessage { diff --git a/src/model/transaction/PersistentDelegationRequestTransaction.ts b/src/model/transaction/PersistentDelegationRequestTransaction.ts index 8396fa08ec..5932445bb5 100644 --- a/src/model/transaction/PersistentDelegationRequestTransaction.ts +++ b/src/model/transaction/PersistentDelegationRequestTransaction.ts @@ -27,7 +27,7 @@ export class PersistentDelegationRequestTransaction extends TransferTransaction * Create a PersistentDelegationRequestTransaction with special message payload * for presistent harvesting delegation unlocking * @param deadline - The deadline to include the transaction. - * @param signingPrivateKey - Remote harvester signing private key linked to the main account + * @param remoteLinkedPrivateKey - Remote harvester signing private key linked to the main account * @param vrfPrivateKey - VRF private key linked to the main account * @param nodePublicKey - Node certificate public key * @param networkType - The network type. @@ -38,7 +38,7 @@ export class PersistentDelegationRequestTransaction extends TransferTransaction */ public static createPersistentDelegationRequestTransaction( deadline: Deadline, - signingPrivateKey: string, + remoteLinkedPrivateKey: string, vrfPrivateKey: string, nodePublicKey: string, networkType: NetworkType, @@ -46,7 +46,7 @@ export class PersistentDelegationRequestTransaction extends TransferTransaction signature?: string, signer?: PublicAccount, ): PersistentDelegationRequestTransaction { - const message = PersistentHarvestingDelegationMessage.create(signingPrivateKey, vrfPrivateKey, nodePublicKey, networkType); + const message = PersistentHarvestingDelegationMessage.create(remoteLinkedPrivateKey, vrfPrivateKey, nodePublicKey, networkType); return super.create( deadline, Address.createFromPublicKey(nodePublicKey, networkType), diff --git a/test/core/utils/TransactionMapping.spec.ts b/test/core/utils/TransactionMapping.spec.ts index 4cddc5c1ad..99c2197d96 100644 --- a/test/core/utils/TransactionMapping.spec.ts +++ b/test/core/utils/TransactionMapping.spec.ts @@ -1631,7 +1631,7 @@ describe('TransactionMapping - createFromDTO (Transaction.toJSON() feed)', () => it('should create from payload with persistent delegate message', () => { const transferTransaction = TransactionMapping.createFromPayload( - '2401000000000000B69B5CB2CE79B5E06117D246E84CB21095BAC0E78A4F01E2D4E3F068EF2E3370B907495FE6BC9A130D05A8BDB49E8AD398FBA40569C921907297AB0D5778C00D2D13E2FDC654936417899AB63D709B9A7A603BA1D20557AA06CE5B2C9242F035000000000198544140420F00000000009A19B31107000000981E13520236DBBD06F8C08710289BD9CF598A01C29E04668400000000000000E201735761802AFECBD67E2DBA5D69157CE32874EFDD680E41B1BFFD12B781F84E8AD883920BBB50EA38AFE078E99EE5EE4BDFDA77E8C101EBD3100C0D471673471A61B23E513FC7E21F7803316B906A688F14AA75002913A3B57DD13469BC27CF8C82FD5C4C76867011AEDC7C4870D8C5AF9C175F0DA5A8E2AD3A327D868BFBA34A5E3D', + '2401000000000000B69B5CB2CE79B5E06117D246E84CB21095BAC0E78A4F01E2D4E3F068EF2E3370B907495FE6BC9A130D05A8BDB49E8AD398FBA40569C921907297AB0D5778C00D2D13E2FDC654936417899AB63D709B9A7A603BA1D20557AA06CE5B2C9242F035000000000198544140420F00000000009A19B31107000000981E13520236DBBD06F8C08710289BD9CF598A01C29E04668400000000000000FE2A8061577301E2CBD67E2DBA5D69157CE32874EFDD680E41B1BFFD12B781F84E8AD883920BBB50EA38AFE078E99EE5EE4BDFDA77E8C101EBD3100C0D471673471A61B23E513FC7E21F7803316B906A688F14AA75002913A3B57DD13469BC27CF8C82FD5C4C76867011AEDC7C4870D8C5AF9C175F0DA5A8E2AD3A327D868BFBA34A5E3D', ) as TransferTransaction; expect(transferTransaction.message.type).eq(MessageType.PersistentHarvestingDelegationMessage); diff --git a/test/model/message/EncryptedMessage.spec.ts b/test/model/message/EncryptedMessage.spec.ts index 9bca46d06a..c081e25a37 100644 --- a/test/model/message/EncryptedMessage.spec.ts +++ b/test/model/message/EncryptedMessage.spec.ts @@ -15,11 +15,10 @@ */ import { expect } from 'chai'; -import { Account } from '../../../src/model/account/Account'; -import { EncryptedMessage } from '../../../src/model/message/EncryptedMessage'; -import { NetworkType } from '../../../src/model/network/NetworkType'; -import { Deadline } from '../../../src/model/transaction/Deadline'; -import { TransferTransaction } from '../../../src/model/transaction/TransferTransaction'; +import { Account } from '../../../src/model/account'; +import { EncryptedMessage } from '../../../src/model/message'; +import { NetworkType } from '../../../src/model/network'; +import { Deadline, TransferTransaction } from '../../../src/model/transaction'; import { NetworkCurrencyLocal } from '../mosaic/Currency.spec'; describe('EncryptedMessage', () => { diff --git a/test/model/message/Message.spec.ts b/test/model/message/Message.spec.ts index 4114bfc3c3..d80eb6c7d4 100644 --- a/test/model/message/Message.spec.ts +++ b/test/model/message/Message.spec.ts @@ -15,11 +15,8 @@ */ import { expect } from 'chai'; -import { Convert } from '../../../src/core/format/Convert'; -import { EncryptedMessage } from '../../../src/model/message/EncryptedMessage'; -import { Message } from '../../../src/model/message/Message'; -import { PersistentHarvestingDelegationMessage } from '../../../src/model/message/PersistentHarvestingDelegationMessage'; -import { PlainMessage } from '../../../src/model/message/PlainMessage'; +import { Convert } from '../../../src/core/format'; +import { EncryptedMessage, Message, PersistentHarvestingDelegationMessage, PlainMessage } from '../../../src/model/message'; describe('Message', () => { it('should create an plain message dto object', () => { @@ -32,9 +29,10 @@ describe('Message', () => { expect(message.toDTO()).to.be.equal('01' + Convert.utf8ToHex('test')); }); - it('should create an PersistentHarvestingDelegationMessage message dto object', () => { - const message = new PersistentHarvestingDelegationMessage('746573742D6D657373616765'); - expect(message.toDTO()).to.be.equal('746573742D6D657373616765'); + it('should throw exception on creating PersistentHarvestingDelegationMessage with wrong size', () => { + expect(() => { + new PersistentHarvestingDelegationMessage('746573742D6D657373616765'); + }).to.throw(Error, 'Invalid persistent harvesting delegate payload size! Expected 264 but got 24'); }); it('should throw exception on creating PersistentHarvestingDelegationMessage', () => { diff --git a/test/model/message/PersistentHarvestingDelegationMessage.spec.ts b/test/model/message/PersistentHarvestingDelegationMessage.spec.ts index de95067a18..fe1d2c2715 100644 --- a/test/model/message/PersistentHarvestingDelegationMessage.spec.ts +++ b/test/model/message/PersistentHarvestingDelegationMessage.spec.ts @@ -15,12 +15,10 @@ */ import { expect } from 'chai'; -import { Account } from '../../../src/model/account/Account'; -import { MessageType } from '../../../src/model/message/MessageType'; -import { PersistentHarvestingDelegationMessage } from '../../../src/model/message/PersistentHarvestingDelegationMessage'; -import { NetworkType } from '../../../src/model/network/NetworkType'; -import { Deadline } from '../../../src/model/transaction/Deadline'; -import { PersistentDelegationRequestTransaction } from '../../../src/model/transaction/PersistentDelegationRequestTransaction'; +import { Account } from '../../../src/model/account'; +import { MessageFactory, MessageMarker, MessageType, PersistentHarvestingDelegationMessage } from '../../../src/model/message'; +import { NetworkType } from '../../../src/model/network'; +import { Deadline, PersistentDelegationRequestTransaction } from '../../../src/model/transaction'; describe('PersistentHarvestingDelegationMessage', () => { let sender: Account; @@ -48,24 +46,35 @@ describe('PersistentHarvestingDelegationMessage', () => { recipient.publicKey, NetworkType.PRIVATE_TEST, ); - expect(encryptedMessage.payload.length).to.be.equal(264); + expect(encryptedMessage.payload.length).to.be.equal(PersistentHarvestingDelegationMessage.HEX_PAYLOAD_SIZE); expect(encryptedMessage.type).to.be.equal(MessageType.PersistentHarvestingDelegationMessage); }); + it('should raise and error when not starting on Marker', () => { + const payload = + 'E201735761802AFEDED358F099E318FEB14C367BEC682476A5B05C985C287561F2ECED84BD22C37BAEB5F56' + + '226F8A4DF4C0E65AFD5F29B51C4A88394FD22CAE4FD4489B31D7FF025A16B66006F2F32DB5A8AED18A2A5E10' + + '26092A7D9F3EBAFD1B614CF57FFA75C58BFA8872FC2796764F0AF9A515C095A09F3D9AA2BA41EBE043CB0CE27'; + + expect(() => { + new PersistentHarvestingDelegationMessage(payload); + }).to.throw(Error, 'Invalid persistent harvesting delegate payload! It does not start with FE2A8061577301E2'); + }); + it('should create a PersistentHarvestingDelegation message from a DTO', () => { const payload = - 'CC71C764BFE598FC121A1816D40600FF3CE1F5C8839DF6EA01A04A630CBEC5C8A' + - 'C121C890E95BBDC67E50AD37E2442279D1BA2328FB7A1781C59D2F414AEFCA288CD' + - '7B2D9F38D11C186CBD33869F2BB6A9F617A4696E4841628F1F396478BDDD0046BA264A1820'; - const msgTypeHex = MessageType.PersistentHarvestingDelegationMessage.toString(16).toUpperCase(); - const encryptedMessage = PersistentHarvestingDelegationMessage.createFromPayload(payload); - expect(encryptedMessage.payload.substring(2)).to.be.equal(payload); - expect(encryptedMessage.payload.substring(0, 2)).to.be.equal(msgTypeHex); + 'FE2A8061577301E231539A87767B731A725E8F87926FDA9968701C082D2AC6CD16C6572F4F3047184D6C4A0443CC5D2565838040CC31B7EA0BA4588728110668BE960A28CAFCDC1703C234903937CCD0CDD6F11DBE7AE4C288FE2E2245BD4BE08C1F864E7FB42C4648E19CA53622AA0C2EAEDB47B8A06B157BD47FD6C230193FCC50F1F9'; + const encryptedMessage = MessageFactory.createMessageFromHex(payload); + expect(encryptedMessage.payload).eq(payload); + expect(encryptedMessage.payload.length).eq(PersistentHarvestingDelegationMessage.HEX_PAYLOAD_SIZE); + + const plainMessage = PersistentHarvestingDelegationMessage.decrypt(encryptedMessage, recipient.privateKey); + expect(plainMessage).to.be.equal(signingPrivateKey + vrfPrivateKey); }); it('should throw exception on createFromPayload with wrong format', () => { expect(() => { - PersistentHarvestingDelegationMessage.createFromPayload('test transaction'); + new PersistentHarvestingDelegationMessage('test transaction'); }).to.throw(Error, 'Payload format is not valid hexadecimal string'); }); @@ -76,6 +85,15 @@ describe('PersistentHarvestingDelegationMessage', () => { recipient.publicKey, NetworkType.PRIVATE_TEST, ); + expect(encryptedMessage.payload.indexOf(MessageMarker.PersistentDelegationUnlock)).eq(0); + expect(encryptedMessage.payload.length).eq(264); + + console.log(encryptedMessage.payload); + const parsed = MessageFactory.createMessageFromHex(encryptedMessage.toDTO()); + expect(parsed.type).eq(MessageType.PersistentHarvestingDelegationMessage); + expect(parsed.payload.length).eq(264); + expect(parsed.payload).eq(encryptedMessage.payload); + const plainMessage = PersistentHarvestingDelegationMessage.decrypt(encryptedMessage, recipient.privateKey); expect(plainMessage).to.be.equal(signingPrivateKey + vrfPrivateKey); }); @@ -90,8 +108,8 @@ describe('PersistentHarvestingDelegationMessage', () => { NetworkType.PRIVATE_TEST, ); const signedTransaction = tx.signWith(sender, generationHash); - const encryptMessage = PersistentHarvestingDelegationMessage.createFromPayload( - signedTransaction.payload.substring(322, signedTransaction.payload.length), + const encryptMessage = MessageFactory.createMessageFromHex( + signedTransaction.payload.substring(320, signedTransaction.payload.length), ); const plainMessage = PersistentHarvestingDelegationMessage.decrypt(encryptMessage, recipient.privateKey); expect(plainMessage).to.be.equal(signingPrivateKey + vrfPrivateKey); diff --git a/test/model/message/PlainMessage.spec.ts b/test/model/message/PlainMessage.spec.ts index 444e11098f..be3bff04ad 100644 --- a/test/model/message/PlainMessage.spec.ts +++ b/test/model/message/PlainMessage.spec.ts @@ -26,12 +26,14 @@ describe('PlainMessage', () => { const payload = 'test-message'; const message = new PlainMessage(payload); expect(message.payload).to.be.equal(payload); + expect(message.toDTO()).to.be.equal('00746573742D6D657373616765'); }); it('should createComplete message from payload with static method', () => { const payload = '746573742D6D657373616765'; const message = PlainMessage.createFromPayload(payload); expect(message.payload).to.be.equal('test-message'); + expect(message.toDTO()).to.be.equal('00746573742D6D657373616765'); }); it('should decode hex message', () => { diff --git a/test/model/transaction/TransferTransaction.spec.ts b/test/model/transaction/TransferTransaction.spec.ts index eb76c44e65..156cb4b350 100644 --- a/test/model/transaction/TransferTransaction.spec.ts +++ b/test/model/transaction/TransferTransaction.spec.ts @@ -322,7 +322,7 @@ describe('TransferTransaction', () => { }); it('should load message with persistent message delegate', () => { const messageHex = - 'E201735761802AFE9FB4BD2BA099AFA82DDB0212080CF649F0CB0FADAD7BA4CC04BE51E40A4EF0A27B8E2BEAB595F4075BB5A6A481835F3A6E4BBA63091A5866D90D2B7ACBBF158E51FE074619C4B0FF0C4AFEE1AE9A4D83A5A7A156C91CCA3A319D3279A64A63491E19656F7211760BB36EF6B3263C03837CE00E84FD82B32B721120DE'; + 'FE2A8061577301E29FB4BD2BA099AFA82DDB0212080CF649F0CB0FADAD7BA4CC04BE51E40A4EF0A27B8E2BEAB595F4075BB5A6A481835F3A6E4BBA63091A5866D90D2B7ACBBF158E51FE074619C4B0FF0C4AFEE1AE9A4D83A5A7A156C91CCA3A319D3279A64A63491E19656F7211760BB36EF6B3263C03837CE00E84FD82B32B721120DE'; const payload: TransactionInfoDTO = { meta: { height: '108907', @@ -351,7 +351,6 @@ describe('TransferTransaction', () => { const transferTransaction = transaction as TransferTransaction; expect(transferTransaction.message.payload).eq(messageHex); expect(transferTransaction.message.type).eq(MessageType.PersistentHarvestingDelegationMessage); - console.log(transferTransaction.message.payload); }); it('should throw exception with invalid private key when creating persistentDelegationRequestTransaction', () => {