Skip to content

Commit 8f267f2

Browse files
authored
Merge pull request #215 from AElfProject/feature/new-function-rm
feat: 🎸 use @scure/base instead of bs58
2 parents 223e9c2 + a7038f6 commit 8f267f2

File tree

5 files changed

+364
-178
lines changed

5 files changed

+364
-178
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aelf-sdk",
3-
"version": "3.5.0-beta.9",
3+
"version": "3.5.0-beta.10",
44
"description": "aelf-sdk js library",
55
"type": "module",
66
"main": "dist/aelf.cjs",
@@ -93,14 +93,14 @@
9393
"@aws-crypto/sha256-js": "^5.0.0",
9494
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
9595
"@babel/runtime": "^7.4.5",
96+
"@scure/base": "^2.0.0",
9697
"@scure/bip32": "^2.0.0",
9798
"@typescript-eslint/parser": "^5.47.1",
9899
"babel-plugin-rewire": "^1.2.0",
99100
"bignumber.js": "^9.0.0",
100101
"bip39": "^3.0.2",
101102
"bn.js": "^5.2.1",
102103
"browserify-cipher": "^1.0.1",
103-
"bs58": "^4.0.1",
104104
"buffer": "^5.2.1",
105105
"crypto-js": "^4.2.0",
106106
"elliptic": "^6.4.1",

src/util/formatters.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
* @date 2015
66
*/
77
import descriptor from '@aelfqueen/protobufjs/ext/descriptor/index.js';
8-
import bs58 from 'bs58';
8+
// import bs58 from 'bs58';
9+
import { base58 as bs58 } from '@scure/base';
910
import { base58 } from './utils.js';
1011

1112
const getByteCountByAddress = base58Str => {
1213
// convert a Base58 string to a binary array and get its byte count
13-
const buffer = bs58.decode(base58Str);
14+
// @scure/base returns Uint8Array, convert to Buffer
15+
const decoded = bs58.decode(base58Str);
16+
const buffer = Buffer.from(decoded);
1417
// get byte
1518
const byteCount = buffer.length;
1619
// last four digits are the checksum

src/util/utils.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
*/
55

66
import BigNumber from 'bignumber.js';
7-
import bs58 from 'bs58';
7+
// import bs58 from 'bs58';
8+
import { base58 as bs58 } from '@scure/base';
89
import { UNIT_MAP, UNSIGNED_256_INT } from '../common/unitConstants.js';
910
import sha256 from './sha256.js';
1011

@@ -21,10 +22,13 @@ export const base58 = {
2122
hash = Buffer.from(sha256(result), 'hex');
2223
hash = Buffer.from(sha256(hash), 'hex');
2324
hash = Buffer.from(result.toString('hex') + hash.slice(0, 4).toString('hex'), 'hex');
24-
return bs58.encode(hash);
25+
// Convert Buffer to Uint8Array for @scure/base
26+
return bs58.encode(new Uint8Array(hash));
2527
},
2628
decode(str, encoding) {
27-
const buffer = Buffer.from(bs58.decode(str));
29+
// @scure/base returns Uint8Array, convert to Buffer
30+
const decoded = bs58.decode(str);
31+
const buffer = Buffer.from(decoded);
2832
let data = buffer.slice(0, -4);
2933
let hash = data;
3034
hash = Buffer.from(sha256(hash), 'hex');
@@ -47,10 +51,13 @@ export const chainIdConvertor = {
4751
const bufferTemp = Buffer.alloc(4);
4852
bufferTemp.writeInt32LE(`0x${chainId.toString('16')}`, 0);
4953
const bytes = Buffer.concat([bufferTemp], 3);
50-
return bs58.encode(bytes);
54+
// Convert Buffer to Uint8Array for @scure/base
55+
return bs58.encode(new Uint8Array(bytes));
5156
},
5257
base58ToChainId(base58String) {
53-
return Buffer.concat([bs58.decode(base58String)], 4).readInt32LE(0);
58+
// @scure/base returns Uint8Array, convert to Buffer
59+
const decoded = bs58.decode(base58String);
60+
return Buffer.concat([Buffer.from(decoded)], 4).readInt32LE(0);
5461
}
5562
};
5663

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/**
2+
* @file bs58 compatibility tests
3+
* @description Tests to verify compatibility between bs58 and @scure/base
4+
* This ensures that both implementations produce identical results
5+
*/
6+
7+
import { describe, it, expect } from 'vitest';
8+
import bs58 from 'bs58';
9+
import { base58 as scureBase58 } from '@scure/base';
10+
11+
describe('bs58 Compatibility Tests', () => {
12+
// Test data - various types of input
13+
const testCases = [
14+
{
15+
name: 'simple hex string',
16+
input: '48656c6c6f20576f726c64', // "Hello World" in hex
17+
encoding: 'hex'
18+
},
19+
{
20+
name: 'empty buffer',
21+
input: '',
22+
encoding: 'hex'
23+
},
24+
{
25+
name: 'single byte',
26+
input: 'ff',
27+
encoding: 'hex'
28+
},
29+
{
30+
name: '32 bytes (typical hash)',
31+
input: 'a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456',
32+
encoding: 'hex'
33+
},
34+
{
35+
name: 'address-like data (33 bytes)',
36+
input: 'a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef12345678',
37+
encoding: 'hex'
38+
},
39+
{
40+
name: 'chain ID data (3 bytes)',
41+
input: '123456',
42+
encoding: 'hex'
43+
}
44+
];
45+
46+
describe('Direct encoding/decoding compatibility', () => {
47+
testCases.forEach(({ name, input, encoding }) => {
48+
it(`should produce identical results for ${name}`, () => {
49+
const buffer = Buffer.from(input, encoding);
50+
51+
// Test bs58
52+
const bs58Encoded = bs58.encode(buffer);
53+
const bs58Decoded = bs58.decode(bs58Encoded);
54+
55+
// Test @scure/base with Uint8Array
56+
const uint8Array = new Uint8Array(buffer);
57+
const scureEncoded = scureBase58.encode(uint8Array);
58+
const scureDecoded = scureBase58.decode(scureEncoded);
59+
60+
// Results should be identical
61+
expect(scureEncoded).toBe(bs58Encoded);
62+
expect(Buffer.from(scureDecoded).toString('hex')).toBe(Buffer.from(bs58Decoded).toString('hex'));
63+
});
64+
});
65+
});
66+
67+
describe('Buffer vs Uint8Array conversion', () => {
68+
it('should handle Buffer to Uint8Array conversion correctly', () => {
69+
const testData = '48656c6c6f20576f726c64';
70+
const buffer = Buffer.from(testData, 'hex');
71+
const uint8Array = new Uint8Array(buffer);
72+
73+
// Both should produce same result
74+
const bs58Result = bs58.encode(buffer);
75+
const scureResult = scureBase58.encode(uint8Array);
76+
77+
expect(scureResult).toBe(bs58Result);
78+
});
79+
80+
it('should handle Uint8Array to Buffer conversion correctly', () => {
81+
const testData = '48656c6c6f20576f726c64';
82+
const uint8Array = new Uint8Array(Buffer.from(testData, 'hex'));
83+
84+
const encoded = scureBase58.encode(uint8Array);
85+
const decoded = scureBase58.decode(encoded);
86+
87+
// Convert back to Buffer for comparison
88+
const buffer = Buffer.from(decoded);
89+
expect(buffer.toString('hex')).toBe(testData);
90+
});
91+
});
92+
93+
describe('Edge cases', () => {
94+
it('should handle zero bytes correctly', () => {
95+
const zeroBuffer = Buffer.alloc(10, 0);
96+
const zeroUint8Array = new Uint8Array(zeroBuffer);
97+
98+
const bs58Result = bs58.encode(zeroBuffer);
99+
const scureResult = scureBase58.encode(zeroUint8Array);
100+
101+
expect(scureResult).toBe(bs58Result);
102+
});
103+
104+
it('should handle maximum byte values correctly', () => {
105+
const maxBuffer = Buffer.alloc(10, 0xff);
106+
const maxUint8Array = new Uint8Array(maxBuffer);
107+
108+
const bs58Result = bs58.encode(maxBuffer);
109+
const scureResult = scureBase58.encode(maxUint8Array);
110+
111+
expect(scureResult).toBe(bs58Result);
112+
});
113+
114+
it('should handle mixed byte values correctly', () => {
115+
const mixedBuffer = Buffer.from([0x00, 0xff, 0x7f, 0x80, 0x01, 0xfe]);
116+
const mixedUint8Array = new Uint8Array(mixedBuffer);
117+
118+
const bs58Result = bs58.encode(mixedBuffer);
119+
const scureResult = scureBase58.encode(mixedUint8Array);
120+
121+
expect(scureResult).toBe(bs58Result);
122+
});
123+
});
124+
125+
describe('Round-trip compatibility', () => {
126+
testCases.forEach(({ name, input, encoding }) => {
127+
it(`should maintain data integrity through round-trip for ${name}`, () => {
128+
const originalBuffer = Buffer.from(input, encoding);
129+
const originalUint8Array = new Uint8Array(originalBuffer);
130+
131+
// Encode with @scure/base
132+
const encoded = scureBase58.encode(originalUint8Array);
133+
134+
// Decode with @scure/base
135+
const decoded = scureBase58.decode(encoded);
136+
const resultBuffer = Buffer.from(decoded);
137+
138+
// Should match original
139+
expect(resultBuffer.toString('hex')).toBe(originalBuffer.toString('hex'));
140+
});
141+
});
142+
});
143+
144+
describe('Error handling compatibility', () => {
145+
it('should handle invalid base58 strings similarly', () => {
146+
const invalidStrings = [
147+
'0', // contains invalid character
148+
'O', // contains invalid character
149+
'I', // contains invalid character
150+
'l', // contains invalid character
151+
'invalid!@#', // contains invalid characters
152+
];
153+
154+
invalidStrings.forEach(invalidStr => {
155+
expect(() => bs58.decode(invalidStr)).toThrow();
156+
expect(() => scureBase58.decode(invalidStr)).toThrow();
157+
});
158+
});
159+
160+
it('should handle empty string consistently', () => {
161+
// Empty string might be handled differently by different libraries
162+
const emptyStr = '';
163+
164+
// Test if both throw or both don't throw
165+
let bs58Throws = false;
166+
let scureThrows = false;
167+
168+
try {
169+
bs58.decode(emptyStr);
170+
} catch (e) {
171+
bs58Throws = true;
172+
}
173+
174+
try {
175+
scureBase58.decode(emptyStr);
176+
} catch (e) {
177+
scureThrows = true;
178+
}
179+
180+
// Both should behave the same way
181+
expect(bs58Throws).toBe(scureThrows);
182+
});
183+
});
184+
});

0 commit comments

Comments
 (0)