Skip to content

Commit 9944647

Browse files
Merge pull request #833 from symbol/fix/metadata-utf8-encoding-fix
fix: metadata value non-ascii utf8 encoding issue fixed
2 parents f9f12a6 + 079297d commit 9944647

19 files changed

+135
-134
lines changed

e2e/infrastructure/MetadataHttp.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { deepEqual } from 'assert';
1818
import { expect } from 'chai';
1919
import { firstValueFrom } from 'rxjs';
2020
import { take, toArray } from 'rxjs/operators';
21+
import { Convert } from '../..';
2122
import { MetadataPaginationStreamer, MetadataRepository, Order } from '../../src/infrastructure';
2223
import { Metadata, MetadataType, UInt64 } from '../../src/model';
2324
import { Account, Address } from '../../src/model/account';
@@ -115,7 +116,7 @@ describe('MetadataHttp', () => {
115116
account.address,
116117
UInt64.fromUint(6),
117118
23,
118-
`Test account meta value`,
119+
Convert.utf8ToUint8(`Test account meta value`),
119120
networkType,
120121
helper.maxFee,
121122
);
@@ -140,7 +141,7 @@ describe('MetadataHttp', () => {
140141
UInt64.fromUint(6),
141142
mosaicId,
142143
22,
143-
`Test mosaic meta value`,
144+
Convert.utf8ToUint8(`Test mosaic meta value`),
144145
networkType,
145146
helper.maxFee,
146147
);
@@ -165,7 +166,7 @@ describe('MetadataHttp', () => {
165166
UInt64.fromUint(6),
166167
namespaceId,
167168
25,
168-
`Test namespace meta value`,
169+
Convert.utf8ToUint8(`Test namespace meta value`),
169170
networkType,
170171
helper.maxFee,
171172
);

e2e/infrastructure/TransactionHttp.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ describe('TransactionHttp', () => {
196196
account.address,
197197
UInt64.fromUint(5),
198198
10,
199-
Convert.uint8ToUtf8(new Uint8Array(10)),
199+
new Uint8Array(10),
200200
networkType,
201201
helper.maxFee,
202202
);
@@ -229,7 +229,7 @@ describe('TransactionHttp', () => {
229229
UInt64.fromUint(5),
230230
mosaicId,
231231
10,
232-
Convert.uint8ToUtf8(new Uint8Array(10)),
232+
new Uint8Array(10),
233233
networkType,
234234
helper.maxFee,
235235
);
@@ -323,7 +323,7 @@ describe('TransactionHttp', () => {
323323
UInt64.fromUint(5),
324324
addressAlias,
325325
10,
326-
Convert.uint8ToUtf8(new Uint8Array(10)),
326+
new Uint8Array(10),
327327
networkType,
328328
helper.maxFee,
329329
);

e2e/infrastructure/UnresolvedMapping.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
* limitations under the License.
1515
*/
1616
import { expect } from 'chai';
17-
import { Convert } from '../../src/core/format';
1817
import { Account } from '../../src/model/account';
1918
import { PlainMessage } from '../../src/model/message/PlainMessage';
2019
import { MosaicFlags, MosaicId, MosaicNonce } from '../../src/model/mosaic';
@@ -165,7 +164,7 @@ describe('Unresolved Mapping', () => {
165164
UInt64.fromUint(5),
166165
namespaceIdMosaic,
167166
10,
168-
Convert.uint8ToUtf8(new Uint8Array(10)),
167+
new Uint8Array(10),
169168
networkType,
170169
helper.maxFee,
171170
);

e2e/service/MetadataTransactionService.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ describe('MetadataTransactionService', () => {
9595
key,
9696
mosaicId,
9797
newValue.length,
98-
newValue,
98+
Convert.utf8ToUint8(newValue),
9999
networkType,
100100
helper.maxFee,
101101
);
@@ -121,7 +121,7 @@ describe('MetadataTransactionService', () => {
121121
key,
122122
namespaceId,
123123
newValue.length,
124-
newValue,
124+
Convert.utf8ToUint8(newValue),
125125
networkType,
126126
);
127127

e2e/service/TransactionService.spec.ts

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

1717
import { assert, expect } from 'chai';
1818
import { firstValueFrom } from 'rxjs';
19-
import { Convert } from '../../src/core/format';
2019
import { TransactionRepository } from '../../src/infrastructure/TransactionRepository';
2120
import { Account, Address } from '../../src/model/account';
2221
import { PlainMessage } from '../../src/model/message/PlainMessage';
@@ -136,7 +135,7 @@ describe('TransactionService', () => {
136135
UInt64.fromUint(5),
137136
mosaicAlias,
138137
10,
139-
Convert.uint8ToUtf8(new Uint8Array(10)),
138+
new Uint8Array(10),
140139
networkType,
141140
helper.maxFee,
142141
);

src/core/format/Convert.ts

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class Convert {
2626
public static toByte = (char1: string, char2: string): number => {
2727
const byte = utilities.tryParseByte(char1, char2);
2828
if (undefined === byte) {
29-
throw Error(`unrecognized hex char`);
29+
throw Error(`unrecognized hex char, char1:${char1}, char2:${char2}`);
3030
}
3131
return byte;
3232
};
@@ -148,33 +148,6 @@ export class Convert {
148148
return input & 0xff;
149149
};
150150

151-
/**
152-
* Converts a raw javascript string into a string of single byte characters using utf8 encoding.
153-
* This makes it easier to perform other encoding operations on the string.
154-
* @param {string} input - A raw string
155-
* @return {string} - UTF-8 string
156-
*/
157-
public static rstr2utf8 = (input: string): string => {
158-
let output = '';
159-
160-
for (let n = 0; n < input.length; n++) {
161-
const c = input.charCodeAt(n);
162-
163-
if (128 > c) {
164-
output += String.fromCharCode(c);
165-
} else if (127 < c && 2048 > c) {
166-
output += String.fromCharCode((c >> 6) | 192);
167-
output += String.fromCharCode((c & 63) | 128);
168-
} else {
169-
output += String.fromCharCode((c >> 12) | 224);
170-
output += String.fromCharCode(((c >> 6) & 63) | 128);
171-
output += String.fromCharCode((c & 63) | 128);
172-
}
173-
}
174-
175-
return output;
176-
};
177-
178151
/**
179152
* Convert UTF-8 to hex
180153
* @param {string} input - An UTF-8 string
@@ -190,7 +163,7 @@ export class Convert {
190163
* @return {Uint8Array}
191164
*/
192165
public static utf8ToUint8 = (input: string): Uint8Array => {
193-
const hex = Convert.utf8ToHex(Convert.rstr2utf8(input));
166+
const hex = Convert.utf8ToHex(input);
194167
return Convert.hexToUint8(hex);
195168
};
196169

src/infrastructure/transaction/CreateTransactionFromDTO.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
import { Convert as convert } from '../../core/format';
1716
import { UnresolvedMapping } from '../../core/utils';
1817
import { MessageFactory, MosaicSupplyRevocationTransaction, UInt64 } from '../../model';
1918
import { Address, PublicAccount } from '../../model/account';
@@ -393,7 +392,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr
393392
extractRecipient(transactionDTO.targetAddress),
394393
UInt64.fromHex(transactionDTO.scopedMetadataKey),
395394
transactionDTO.valueSizeDelta,
396-
convert.decodeHex(transactionDTO.value),
395+
transactionDTO.value,
397396
signature,
398397
signer,
399398
transactionInfo,
@@ -408,7 +407,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr
408407
UInt64.fromHex(transactionDTO.scopedMetadataKey),
409408
UnresolvedMapping.toUnresolvedMosaic(transactionDTO.targetMosaicId),
410409
transactionDTO.valueSizeDelta,
411-
convert.decodeHex(transactionDTO.value),
410+
transactionDTO.value,
412411
signature,
413412
signer,
414413
transactionInfo,
@@ -423,7 +422,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr
423422
UInt64.fromHex(transactionDTO.scopedMetadataKey),
424423
NamespaceId.createFromEncoded(transactionDTO.targetNamespaceId),
425424
transactionDTO.valueSizeDelta,
426-
convert.decodeHex(transactionDTO.value),
425+
transactionDTO.value,
427426
signature,
428427
signer,
429428
transactionInfo,

src/infrastructure/transaction/SerializeTransactionToJSON.ts

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

17-
import { Convert } from '../../core/format';
1817
import {
1918
AccountAddressRestrictionTransaction,
2019
AccountKeyLinkTransaction,
@@ -246,7 +245,7 @@ export const SerializeTransactionToJSON = (transaction: Transaction): any => {
246245
scopedMetadataKey: accountMetadataTx.scopedMetadataKey.toHex(),
247246
valueSizeDelta: accountMetadataTx.valueSizeDelta,
248247
valueSize: accountMetadataTx.value.length,
249-
value: Convert.utf8ToHex(accountMetadataTx.value),
248+
value: accountMetadataTx.value,
250249
};
251250
} else if (transaction.type === TransactionType.MOSAIC_METADATA) {
252251
const mosaicMetadataTx = transaction as MosaicMetadataTransaction;
@@ -256,7 +255,7 @@ export const SerializeTransactionToJSON = (transaction: Transaction): any => {
256255
valueSizeDelta: mosaicMetadataTx.valueSizeDelta,
257256
targetMosaicId: mosaicMetadataTx.targetMosaicId.id.toHex(),
258257
valueSize: mosaicMetadataTx.value.length,
259-
value: Convert.utf8ToHex(mosaicMetadataTx.value),
258+
value: mosaicMetadataTx.value,
260259
};
261260
} else if (transaction.type === TransactionType.NAMESPACE_METADATA) {
262261
const namespaceMetaTx = transaction as NamespaceMetadataTransaction;
@@ -266,7 +265,7 @@ export const SerializeTransactionToJSON = (transaction: Transaction): any => {
266265
valueSizeDelta: namespaceMetaTx.valueSizeDelta,
267266
targetNamespaceId: namespaceMetaTx.targetNamespaceId.id.toHex(),
268267
valueSize: namespaceMetaTx.value.length,
269-
value: Convert.utf8ToHex(namespaceMetaTx.value),
268+
value: namespaceMetaTx.value,
270269
};
271270
} else if (transaction.type === TransactionType.VRF_KEY_LINK) {
272271
const vrfKeyLinkTx = transaction as VrfKeyLinkTransaction;

src/model/transaction/AccountMetadataTransaction.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ export class AccountMetadataTransaction extends Transaction {
4646
* @param targetAddress - target account address.
4747
* @param scopedMetadataKey - Metadata key scoped to source, target and type.
4848
* @param valueSizeDelta - Change in value size in bytes.
49-
* @param value - String value with UTF-8 encoding
50-
* Difference between the previous value and new value.
49+
* @param value - Difference between the previous value and new value.
5150
* You can calculate value as xor(previous-value, new-value).
5251
* If there is no previous value, use directly the new value.
5352
* @param maxFee - (Optional) Max fee defined by the sender
@@ -60,7 +59,7 @@ export class AccountMetadataTransaction extends Transaction {
6059
targetAddress: UnresolvedAddress,
6160
scopedMetadataKey: UInt64,
6261
valueSizeDelta: number,
63-
value: string,
62+
value: Uint8Array,
6463
networkType: NetworkType,
6564
maxFee: UInt64 = new UInt64([0, 0]),
6665
signature?: string,
@@ -111,10 +110,10 @@ export class AccountMetadataTransaction extends Transaction {
111110
*/
112111
public readonly valueSizeDelta: number,
113112
/**
114-
* String value with UTF-8 encoding.
113+
* xor of previous and the new value
115114
* Difference between the previous value and new value.
116115
*/
117-
public readonly value: string,
116+
public readonly value: Uint8Array,
118117
signature?: string,
119118
signer?: PublicAccount,
120119
transactionInfo?: TransactionInfo,
@@ -142,7 +141,7 @@ export class AccountMetadataTransaction extends Transaction {
142141
UnresolvedMapping.toUnresolvedAddress(Convert.uint8ToHex(builder.getTargetAddress().unresolvedAddress)),
143142
new UInt64(builder.getScopedMetadataKey()),
144143
builder.getValueSizeDelta(),
145-
Convert.uint8ToUtf8(builder.getValue()),
144+
builder.getValue(),
146145
networkType,
147146
isEmbedded ? new UInt64([0, 0]) : new UInt64((builder as AccountMetadataTransactionBuilder).fee.amount),
148147
signature,
@@ -167,7 +166,7 @@ export class AccountMetadataTransaction extends Transaction {
167166
new UnresolvedAddressDto(this.targetAddress.encodeUnresolvedAddress(this.networkType)),
168167
this.scopedMetadataKey.toDTO(),
169168
this.valueSizeDelta,
170-
Convert.utf8ToUint8(this.value),
169+
this.value,
171170
);
172171
return transactionBuilder;
173172
}
@@ -185,7 +184,7 @@ export class AccountMetadataTransaction extends Transaction {
185184
new UnresolvedAddressDto(this.targetAddress.encodeUnresolvedAddress(this.networkType)),
186185
this.scopedMetadataKey.toDTO(),
187186
this.valueSizeDelta,
188-
Convert.utf8ToUint8(this.value),
187+
this.value,
189188
);
190189
}
191190

src/model/transaction/MosaicMetadataTransaction.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ export class MosaicMetadataTransaction extends Transaction {
5151
* @param scopedMetadataKey - Metadata key scoped to source, target and type.
5252
* @param targetMosaicId - Target unresolved mosaic identifier.
5353
* @param valueSizeDelta - Change in value size in bytes.
54-
* @param value - String value with UTF-8 encoding
55-
* Difference between the previous value and new value.
54+
* @param value - Difference between the previous value and new value.
5655
* You can calculate value as xor(previous-value, new-value).
5756
* If there is no previous value, use directly the new value.
5857
* @param maxFee - (Optional) Max fee defined by the sender
@@ -66,7 +65,7 @@ export class MosaicMetadataTransaction extends Transaction {
6665
scopedMetadataKey: UInt64,
6766
targetMosaicId: UnresolvedMosaicId,
6867
valueSizeDelta: number,
69-
value: string,
68+
value: Uint8Array,
7069
networkType: NetworkType,
7170
maxFee: UInt64 = new UInt64([0, 0]),
7271
signature?: string,
@@ -123,10 +122,10 @@ export class MosaicMetadataTransaction extends Transaction {
123122
*/
124123
public readonly valueSizeDelta: number,
125124
/**
126-
* String value with UTF-8 encoding.
125+
* xor of previous and the new value
127126
* Difference between the previous value and new value.
128127
*/
129-
public readonly value: string,
128+
public readonly value: Uint8Array,
130129
signature?: string,
131130
signer?: PublicAccount,
132131
transactionInfo?: TransactionInfo,
@@ -155,7 +154,7 @@ export class MosaicMetadataTransaction extends Transaction {
155154
new UInt64(builder.getScopedMetadataKey()),
156155
UnresolvedMapping.toUnresolvedMosaic(new UInt64(builder.getTargetMosaicId().unresolvedMosaicId).toHex()),
157156
builder.getValueSizeDelta(),
158-
Convert.uint8ToUtf8(builder.getValue()),
157+
builder.getValue(),
159158
networkType,
160159
isEmbedded ? new UInt64([0, 0]) : new UInt64((builder as MosaicMetadataTransactionBuilder).fee.amount),
161160
signature,
@@ -181,7 +180,7 @@ export class MosaicMetadataTransaction extends Transaction {
181180
this.scopedMetadataKey.toDTO(),
182181
new UnresolvedMosaicIdDto(this.targetMosaicId.id.toDTO()),
183182
this.valueSizeDelta,
184-
Convert.utf8ToUint8(this.value),
183+
this.value,
185184
);
186185
return transactionBuilder;
187186
}
@@ -200,7 +199,7 @@ export class MosaicMetadataTransaction extends Transaction {
200199
this.scopedMetadataKey.toDTO(),
201200
new UnresolvedMosaicIdDto(this.targetMosaicId.id.toDTO()),
202201
this.valueSizeDelta,
203-
Convert.utf8ToUint8(this.value),
202+
this.value,
204203
);
205204
}
206205

0 commit comments

Comments
 (0)