Skip to content

Commit 89d73f1

Browse files
Merge pull request #835 from symbol/fix/metadata-value-serialization
fix: metadata value ser/deser is fixed
2 parents aef6b6e + aa700ac commit 89d73f1

File tree

6 files changed

+297
-9
lines changed

6 files changed

+297
-9
lines changed

src/core/crypto/Utilities.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
import * as CryptoJS from 'crypto-js';
18-
import { WordArray } from 'crypto-js';
1918
import * as hkdf from 'futoin-hkdf';
2019
import { sha512 } from 'js-sha512';
2120
import { RawArray as array } from '../format';
@@ -34,7 +33,7 @@ export const Half_Hash_Size = Hash_Size / 2;
3433
*
3534
* @return {WordArray}
3635
*/
37-
export const ua2words = (ua, uaLength): WordArray => {
36+
export const ua2words = (ua, uaLength): any => {
3837
const temp: number[] = [];
3938
for (let i = 0; i < uaLength; i += 4) {
4039
const x = ua[i] * 0x1000000 + (ua[i + 1] || 0) * 0x10000 + (ua[i + 2] || 0) * 0x100 + (ua[i + 3] || 0);

src/infrastructure/transaction/CreateTransactionFromDTO.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
import { Convert } from '../..';
1617
import { UnresolvedMapping } from '../../core/utils';
1718
import { MessageFactory, MosaicSupplyRevocationTransaction, UInt64 } from '../../model';
1819
import { Address, PublicAccount } from '../../model/account';
@@ -392,7 +393,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr
392393
extractRecipient(transactionDTO.targetAddress),
393394
UInt64.fromHex(transactionDTO.scopedMetadataKey),
394395
transactionDTO.valueSizeDelta,
395-
transactionDTO.value,
396+
Convert.hexToUint8(transactionDTO.value),
396397
signature,
397398
signer,
398399
transactionInfo,
@@ -407,7 +408,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr
407408
UInt64.fromHex(transactionDTO.scopedMetadataKey),
408409
UnresolvedMapping.toUnresolvedMosaic(transactionDTO.targetMosaicId),
409410
transactionDTO.valueSizeDelta,
410-
transactionDTO.value,
411+
Convert.hexToUint8(transactionDTO.value),
411412
signature,
412413
signer,
413414
transactionInfo,
@@ -422,7 +423,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr
422423
UInt64.fromHex(transactionDTO.scopedMetadataKey),
423424
NamespaceId.createFromEncoded(transactionDTO.targetNamespaceId),
424425
transactionDTO.valueSizeDelta,
425-
transactionDTO.value,
426+
Convert.hexToUint8(transactionDTO.value),
426427
signature,
427428
signer,
428429
transactionInfo,

src/infrastructure/transaction/SerializeTransactionToJSON.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { Convert } from '../..';
1718
import {
1819
AccountAddressRestrictionTransaction,
1920
AccountKeyLinkTransaction,
@@ -245,7 +246,7 @@ export const SerializeTransactionToJSON = (transaction: Transaction): any => {
245246
scopedMetadataKey: accountMetadataTx.scopedMetadataKey.toHex(),
246247
valueSizeDelta: accountMetadataTx.valueSizeDelta,
247248
valueSize: accountMetadataTx.value.length,
248-
value: accountMetadataTx.value,
249+
value: Convert.uint8ToHex(accountMetadataTx.value),
249250
};
250251
} else if (transaction.type === TransactionType.MOSAIC_METADATA) {
251252
const mosaicMetadataTx = transaction as MosaicMetadataTransaction;
@@ -255,7 +256,7 @@ export const SerializeTransactionToJSON = (transaction: Transaction): any => {
255256
valueSizeDelta: mosaicMetadataTx.valueSizeDelta,
256257
targetMosaicId: mosaicMetadataTx.targetMosaicId.id.toHex(),
257258
valueSize: mosaicMetadataTx.value.length,
258-
value: mosaicMetadataTx.value,
259+
value: Convert.uint8ToHex(mosaicMetadataTx.value),
259260
};
260261
} else if (transaction.type === TransactionType.NAMESPACE_METADATA) {
261262
const namespaceMetaTx = transaction as NamespaceMetadataTransaction;
@@ -265,7 +266,7 @@ export const SerializeTransactionToJSON = (transaction: Transaction): any => {
265266
valueSizeDelta: namespaceMetaTx.valueSizeDelta,
266267
targetNamespaceId: namespaceMetaTx.targetNamespaceId.id.toHex(),
267268
valueSize: namespaceMetaTx.value.length,
268-
value: namespaceMetaTx.value,
269+
value: Convert.uint8ToHex(namespaceMetaTx.value),
269270
};
270271
} else if (transaction.type === TransactionType.VRF_KEY_LINK) {
271272
const vrfKeyLinkTx = transaction as VrfKeyLinkTransaction;

test/infrastructure/SerializeTransactionToJSON.spec.ts

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,16 @@ import { sha3_256 } from 'js-sha3';
1919
import { Crypto } from '../../src/core/crypto';
2020
import { Convert as convert, Convert } from '../../src/core/format';
2121
import { TransactionMapping } from '../../src/core/utils';
22-
import { Mosaic, MosaicSupplyRevocationTransaction, Transaction, TransactionVersion, UInt64 } from '../../src/model';
22+
import {
23+
AccountMetadataTransaction,
24+
Mosaic,
25+
MosaicMetadataTransaction,
26+
MosaicSupplyRevocationTransaction,
27+
NamespaceMetadataTransaction,
28+
Transaction,
29+
TransactionVersion,
30+
UInt64,
31+
} from '../../src/model';
2332
import { Account, Address } from '../../src/model/account';
2433
import { LockHashAlgorithm } from '../../src/model/lock';
2534
import { PlainMessage } from '../../src/model/message';
@@ -443,4 +452,86 @@ describe('SerializeTransactionToJSON', () => {
443452
expect(json.transaction.endEpoch).to.be.equal(3);
444453
expect(json.transaction.linkAction).to.be.equal(LinkAction.Link);
445454
});
455+
456+
describe('Metadata Transactions', () => {
457+
const baseMetadataTxTest = (expectedValue: Uint8Array, metadataTransaction: Transaction) => {
458+
// act
459+
const json = validateToFromJson(metadataTransaction);
460+
461+
// assert
462+
expect(json.transaction.scopedMetadataKey).to.be.equal('00000000000003E8');
463+
expect(json.transaction.valueSize).to.be.equal(expectedValue.length);
464+
expect(json.transaction.valueSizeDelta).to.be.equal(expectedValue.length);
465+
expect(json.transaction.version).to.be.equal(1);
466+
467+
return json;
468+
};
469+
470+
it('should create AccountMetadataTransaction', () => {
471+
// arrange
472+
const value = Convert.utf8ToUint8('This is the message for this account! 汉字89664');
473+
const accountMetadataTransaction = AccountMetadataTransaction.create(
474+
Deadline.create(epochAdjustment),
475+
account.address,
476+
UInt64.fromUint(1000),
477+
value.length,
478+
value,
479+
NetworkType.TEST_NET,
480+
);
481+
482+
// act & assert
483+
const json = baseMetadataTxTest(value, accountMetadataTransaction);
484+
485+
// assert more
486+
expect(json.transaction.value).to.be.equal(
487+
'5468697320697320746865206D65737361676520666F722074686973206163636F756E742120E6B189E5AD973839363634',
488+
);
489+
});
490+
491+
it('should create MosaicMetadataTransaction', () => {
492+
// arrange
493+
const value = Convert.utf8ToUint8('This is the message for this mosaic! 汉字89664');
494+
const mosaicMetadataTransaction = MosaicMetadataTransaction.create(
495+
Deadline.create(epochAdjustment),
496+
account.address,
497+
UInt64.fromUint(1000),
498+
new MosaicId([2262289484, 3405110546]),
499+
value.length,
500+
value,
501+
NetworkType.TEST_NET,
502+
);
503+
504+
// act & assert
505+
const json = baseMetadataTxTest(value, mosaicMetadataTransaction);
506+
507+
// assert more
508+
expect(json.transaction.targetMosaicId).to.be.equal('CAF5DD1286D7CC4C');
509+
expect(json.transaction.value).to.be.equal(
510+
'5468697320697320746865206D65737361676520666F722074686973206D6F736169632120E6B189E5AD973839363634',
511+
);
512+
});
513+
514+
it('should create NamespaceMetadataTransaction', () => {
515+
// arrange
516+
const value = Convert.utf8ToUint8('This is the message for this namespace! 汉字89664');
517+
const namespaceMetadataTransaction = NamespaceMetadataTransaction.create(
518+
Deadline.create(epochAdjustment),
519+
account.address,
520+
UInt64.fromUint(1000),
521+
new NamespaceId([929036875, 2226345261]),
522+
value.length,
523+
value,
524+
NetworkType.TEST_NET,
525+
);
526+
527+
// act & assert
528+
const json = baseMetadataTxTest(value, namespaceMetadataTransaction);
529+
530+
// assert more
531+
expect(json.transaction.targetNamespaceId).to.be.equal('84B3552D375FFA4B');
532+
expect(json.transaction.value).to.be.equal(
533+
'5468697320697320746865206D65737361676520666F722074686973206E616D6573706163652120E6B189E5AD973839363634',
534+
);
535+
});
536+
});
446537
});

test/infrastructure/transaction/CreateTransactionFromDTO.spec.ts

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import {
2121
NamespaceRegistrationTypeEnum,
2222
NetworkTypeEnum,
2323
TransactionInfoDTO,
24+
TransactionTypeEnum,
2425
TransferTransactionDTO,
2526
} from 'symbol-openapi-typescript-fetch-client';
27+
import { MosaicId, NamespaceId } from '../../..';
2628
import { CreateTransactionFromDTO } from '../../../src/infrastructure/transaction';
2729
import { Address } from '../../../src/model/account';
2830
import { TransferTransaction } from '../../../src/model/transaction';
@@ -708,4 +710,171 @@ describe('CreateTransactionFromDTO', () => {
708710
);
709711
});
710712
});
713+
714+
describe('Metadata Transactions', () => {
715+
// standalone tx constants
716+
const testTxSignature =
717+
'7442156D839A3AC900BC0299E8701ECDABA674DCF91283223450953B005DE72C538EA54236F5E089530074CE78067CD3325CF53750B9118154C08B20A5CDC00D';
718+
const testTxSignerPublicKey = '2FC3872A792933617D70E02AFF8FBDE152821A0DF0CA5FB04CB56FC3D21C8863';
719+
const testTxDeadline = '71756535303';
720+
const testTxHeight = '1';
721+
const testTxHash = '533243B8575C4058F894C453160AFF055A4A905978AC331460F44104D831E4AC';
722+
const testTxMerkleComponentHash = '533243B8575C4058F894C453160AFF055A4A905978AC331460F44104D831E4AC';
723+
const testTxId = '5CD2B76B2B3F0F0001751380';
724+
const testTxIndex = 0;
725+
const testTxSize = 100;
726+
const testTxMaxFee = '0';
727+
728+
// aggregate tx constants
729+
const testAggTxId = '5A0069D83F17CF0001777E55';
730+
const testAggTxHash = '671653C94E2254F2A23EFEDB15D67C38332AED1FBD24B063C0A8E675582B6A96';
731+
const testAggTxHeight = '1860';
732+
const testAggTxIndex = 0;
733+
const testAggMerkleComponentHash = '81E5E7AE49998802DABC816EC10158D3A7879702FF29084C2C992CD1289877A7';
734+
const testAggTxSize = 100;
735+
const testAggTxCosigSignature =
736+
'5780C8DF9D46BA2BCF029DCC5D3BF55FE1CB5BE7ABCF30387C4637DD' +
737+
'EDFC2152703CA0AD95F21BB9B942F3CC52FCFC2064C7B84CF60D1A9E69195F1943156C07';
738+
const testAggCosigSignerPublicKey = 'A5F82EC8EBB341427B6785C8111906CD0DF18838FB11B51CE0E18B5E79DFF630';
739+
const testAggTxDeadline = '1000';
740+
const testAggTxMaxFee = '0';
741+
const testAggTxSignature =
742+
'939673209A13FF82397578D22CC96EB8516A6760C894D9B7535E3A1E0680' +
743+
'07B9255CFA9A914C97142A7AE18533E381C846B69D2AE0D60D1DC8A55AD120E2B606';
744+
const testAggTxSignerPublicKey = '7681ED5023141D9CDCF184E5A7B60B7D466739918ED5DA30F7E71EA7B86EFF2D';
745+
746+
// metadata tx constants
747+
const testTargetAddress = 'TATNE7Q5BITMUTRRN6IB4I7FLSDRDWZA37JGO5Q';
748+
const testScopedMedataKey = '00000000000003E8';
749+
750+
const prepBaseTxDto = (txType: TransactionTypeEnum) => ({
751+
signerPublicKey: testTxSignerPublicKey,
752+
version: 1,
753+
network: NetworkTypeEnum.NUMBER_152,
754+
type: txType,
755+
maxFee: testTxMaxFee,
756+
deadline: testTxDeadline,
757+
});
758+
759+
const prepAggregateTxDto = (innerTransaction) => ({
760+
id: testAggTxId,
761+
meta: {
762+
hash: testAggTxHash,
763+
height: testAggTxHeight,
764+
index: testAggTxIndex,
765+
merkleComponentHash: testAggMerkleComponentHash,
766+
},
767+
transaction: {
768+
size: testAggTxSize,
769+
cosignatures: [
770+
{
771+
version: '0',
772+
signature: testAggTxCosigSignature,
773+
signerPublicKey: testAggCosigSignerPublicKey,
774+
},
775+
],
776+
deadline: testAggTxDeadline,
777+
maxFee: testAggTxMaxFee,
778+
signature: testAggTxSignature,
779+
signerPublicKey: testAggTxSignerPublicKey,
780+
transactions: [
781+
{
782+
id: testTxId,
783+
meta: {
784+
aggregateHash: testAggTxHash,
785+
aggregateId: testAggTxId,
786+
height: testAggTxHeight,
787+
index: testAggTxIndex,
788+
},
789+
transaction: innerTransaction,
790+
},
791+
],
792+
type: 16705,
793+
version: 1,
794+
network: NetworkTypeEnum.NUMBER_152,
795+
},
796+
});
797+
798+
const prepStandaloneTxDto = (transactionDto) => ({
799+
id: testTxId,
800+
meta: {
801+
height: testTxHeight,
802+
hash: testTxHash,
803+
merkleComponentHash: testTxMerkleComponentHash,
804+
index: testTxIndex,
805+
},
806+
transaction: transactionDto,
807+
});
808+
809+
const prepTransactionDto = (txDetails) => ({
810+
size: testTxSize,
811+
signature: testTxSignature,
812+
...txDetails,
813+
});
814+
815+
const testStandaloneAndAggregate = (baseMetadataTxDto, txType) => {
816+
it('standalone', () => {
817+
// arrange
818+
const metadataTransactionDto: TransactionInfoDTO = prepStandaloneTxDto(prepTransactionDto(baseMetadataTxDto));
819+
820+
// act
821+
const metadataTransaction = CreateTransactionFromDTO(metadataTransactionDto);
822+
823+
// assert
824+
expect(metadataTransaction.type).eq(txType);
825+
expect(metadataTransaction.size).eq(testTxSize);
826+
ValidateTransaction.validateStandaloneTx(metadataTransaction, metadataTransactionDto);
827+
});
828+
829+
it('aggregate', () => {
830+
// arrange
831+
const aggregateMetadataTransactionDto = prepAggregateTxDto(baseMetadataTxDto);
832+
833+
// act
834+
const aggregateMetadataTransaction = CreateTransactionFromDTO(aggregateMetadataTransactionDto);
835+
836+
// assert
837+
expect(aggregateMetadataTransaction.size).eq(testAggTxSize);
838+
ValidateTransaction.validateAggregateTx(aggregateMetadataTransaction, aggregateMetadataTransactionDto);
839+
});
840+
};
841+
842+
describe('AccountMetadataTransaction', () => {
843+
const baseAccountMetadataTxDto = {
844+
...prepBaseTxDto(TransactionTypeEnum.NUMBER_16708),
845+
targetAddress: testTargetAddress,
846+
scopedMetadataKey: testScopedMedataKey,
847+
valueSizeDelta: 49,
848+
valueSize: 49,
849+
value: '5468697320697320746865206D65737361676520666F722074686973206163636F756E742120E6B189E5AD973839363634',
850+
};
851+
testStandaloneAndAggregate(baseAccountMetadataTxDto, TransactionTypeDto.ACCOUNT_METADATA);
852+
});
853+
854+
describe('MosaicMetadataTransaction', () => {
855+
const baseMosaicMetadataTxDto = {
856+
...prepBaseTxDto(TransactionTypeEnum.NUMBER_16964),
857+
targetAddress: testTargetAddress,
858+
scopedMetadataKey: testScopedMedataKey,
859+
targetMosaicId: new MosaicId([2262289484, 3405110546]).toHex(),
860+
valueSizeDelta: 48,
861+
valueSize: 48,
862+
value: '5468697320697320746865206D65737361676520666F722074686973206D6F736169632120E6B189E5AD973839363634',
863+
};
864+
testStandaloneAndAggregate(baseMosaicMetadataTxDto, TransactionTypeDto.MOSAIC_METADATA);
865+
});
866+
867+
describe('NamespaceMetadataTransaction', () => {
868+
const baseNamespaceMetadataTxDto = {
869+
...prepBaseTxDto(TransactionTypeEnum.NUMBER_17220),
870+
targetAddress: testTargetAddress,
871+
scopedMetadataKey: testScopedMedataKey,
872+
targetNamespaceId: new NamespaceId([929036875, 2226345261]).toHex(),
873+
valueSizeDelta: 51,
874+
valueSize: 51,
875+
value: '5468697320697320746865206D65737361676520666F722074686973206E616D6573706163652120E6B189E5AD973839363634',
876+
};
877+
testStandaloneAndAggregate(baseNamespaceMetadataTxDto, TransactionTypeDto.NAMESPACE_METADATA);
878+
});
879+
});
711880
});

0 commit comments

Comments
 (0)