Skip to content

Commit befc849

Browse files
authored
chore: backport (#1808)
1 parent 7d907dc commit befc849

File tree

26 files changed

+275
-204
lines changed

26 files changed

+275
-204
lines changed

docker/rpc-proxy/Dockerfile

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ RUN /bin/sh ./adjust-packages.sh ./
2727
# Stage 2: Serve the app using node
2828
FROM node:20.17.0-alpine3.20 AS runner
2929

30+
# Update package list and upgrade OpenSSL
31+
RUN apk update && \
32+
apk add --no-cache openssl && \
33+
apk upgrade --no-cache openssl && \
34+
# Verify OpenSSL installation
35+
openssl version && \
36+
# Clean up
37+
rm -rf /var/cache/apk/*
38+
3039
# Copy only the built files and essential runtime files from the builder stage
3140
## rpc-proxy
3241
COPY --from=builder /app/packages/rpc-proxy/dist /app/packages/rpc-proxy/dist

packages/core/src/vcdm/Revision.ts

+47-38
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,44 @@
11
import { InvalidDataType } from '@vechain/sdk-errors';
22
import { Hex } from './Hex';
3-
import { HexUInt } from './HexUInt';
43
import { Txt } from './Txt';
54

65
/**
7-
* Represents a revision for a Thor transaction or block.
8-
*
9-
* @remarks The string representation of the revision is always expressed as a number in base 10.
6+
* Represents a revision for a Thor transaction or block
7+
* Revision strings can be one of the following:
8+
* - "best": indicating the best revision
9+
* - "finalized": indicating a finalized revision
10+
* - "next": indicating the next revision
11+
* - "justified": indicating the justified revision
12+
* - A hex string prefixed with "0x" indicating a specific block id
13+
* - A positive number indicating a specific block number
1014
*
1115
* @extends Txt
1216
*/
1317
class Revision extends Txt {
1418
/**
1519
* Regular expression pattern for revision strings.
16-
* Revision strings can be one of the following:
17-
* - "best": indicating the best revision
18-
* - "finalized": indicating a finalized revision
19-
* - A positive numeric string indicating a specific revision
2020
*
2121
* @type {RegExp}
2222
*/
23-
private static readonly REGEX_DECIMAL_REVISION = /^(best|finalized|\d+)$/;
23+
private static readonly VALID_REVISION_REGEX =
24+
/^(best|finalized|next|justified|0x[a-fA-F0-9]+|\d+)$/;
2425

2526
/**
26-
* Determines if the given value is valid.
27-
* This is true if the given value is
28-
* - "best" string or {@link Txt}: indicating the best revision;
29-
* - "finalized" string or {@link Txt}: indicating a finalized revision;
30-
* - a positive number;
31-
* - a positive numeric decimal or `0x` prefixed hexadecimal string indicating a specific revision,
32-
*
33-
* @param {bigint | number | string | Hex | Txt} value - The value to be validated.
27+
* Determines if the given value is a valid revision.
28+
* @param {bigint| number | string | Hex} value - The value to be validated.
3429
* @returns {boolean} - Returns `true` if the value is valid, `false` otherwise.
3530
*/
36-
public static isValid(value: number | string): boolean {
31+
public static isValid(value: bigint | number | string | Hex): boolean {
3732
if (typeof value === 'number') {
3833
return Number.isInteger(value) && value >= 0;
3934
}
40-
return (
41-
HexUInt.isValid0x(value) ||
42-
Revision.REGEX_DECIMAL_REVISION.test(value)
43-
);
35+
if (typeof value === 'bigint') {
36+
return value >= BigInt(0);
37+
}
38+
if (value instanceof Hex) {
39+
return Revision.isValid(value.bi);
40+
}
41+
return Revision.VALID_REVISION_REGEX.test(value);
4442
}
4543

4644
/**
@@ -59,24 +57,25 @@ class Revision extends Txt {
5957
*/
6058
public static of(value: bigint | number | string | Uint8Array | Hex): Txt {
6159
try {
62-
let txt: string;
63-
if (value instanceof Hex) {
64-
txt = value.bi.toString();
65-
} else if (
66-
typeof value === 'bigint' ||
67-
typeof value === 'number' ||
68-
typeof value === 'string'
69-
) {
70-
txt = `${value}`;
71-
} else {
72-
txt = Txt.of(value).toString();
60+
// handle Uint8Array which is needed to extend Txt.of
61+
if (ArrayBuffer.isView(value)) {
62+
const txtValue = Txt.of(value).toString();
63+
if (Revision.isValid(txtValue)) {
64+
return new Revision(txtValue);
65+
} else {
66+
throw new InvalidDataType('Revision.of', 'not a revision', {
67+
value: `${value}`
68+
});
69+
}
7370
}
74-
if (Revision.isValid(txt)) {
75-
return new Revision(txt);
71+
// handle other types
72+
if (Revision.isValid(value)) {
73+
return new Revision(`${value}`);
74+
} else {
75+
throw new InvalidDataType('Revision.of', 'not a revision', {
76+
value: `${value}`
77+
});
7678
}
77-
throw new InvalidDataType('Revision.of', 'not a revision', {
78-
value: `${value}`
79-
});
8079
} catch (e) {
8180
throw new InvalidDataType('Revision.of', 'not a revision', {
8281
value: `${value}`,
@@ -94,6 +93,16 @@ class Revision extends Txt {
9493
* Return the `finalized` revision instance.
9594
*/
9695
public static readonly FINALIZED: Revision = Revision.of('finalized');
96+
97+
/**
98+
* Return the `next` revision instance.
99+
*/
100+
public static readonly NEXT: Revision = Revision.of('next');
101+
102+
/**
103+
* Return the `justified` revision instance.
104+
*/
105+
public static readonly JUSTIFIED: Revision = Revision.of('justified');
97106
}
98107

99108
export { Revision };

packages/core/tests/vcdm/Revision.unit.test.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('Revision class tests', () => {
3131
expect(Revision.isValid('123.57')).toBeFalsy();
3232
});
3333

34-
test('Return false for not numeric nor `best` nor `finalized` value', () => {
34+
test('Return false for not numeric not a block tag', () => {
3535
expect(Revision.isValid('ABadBabe')).toBeFalsy();
3636
});
3737

@@ -54,6 +54,9 @@ describe('Revision class tests', () => {
5454
test('Return true for `finalized` value', () => {
5555
expect(Revision.isValid('finalized')).toBeTruthy();
5656
});
57+
test('Return true for `next` value', () => {
58+
expect(Revision.isValid('next')).toBeTruthy();
59+
});
5760
});
5861
});
5962

packages/errors/src/available-errors/provider/provider.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ class JSONRPCInternalError extends JSONRPCProviderError {
118118
}
119119
}
120120

121+
/**
122+
* Invalid default block.
123+
*
124+
* WHEN TO USE:
125+
* * When converting default block to vechain revision
126+
*/
127+
class JSONRPCInvalidDefaultBlock extends VechainSDKError<string> {}
128+
121129
/**
122130
* Server error.
123131
*
@@ -143,5 +151,6 @@ export {
143151
JSONRPCParseError,
144152
JSONRPCProviderError,
145153
JSONRPCServerError,
146-
ProviderMethodError
154+
ProviderMethodError,
155+
JSONRPCInvalidDefaultBlock
147156
};
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,59 @@
1-
import { Hex } from '@vechain/sdk-core';
2-
import { type BlockQuantityInputRPC } from '../../rpc-mapper/types';
1+
import { HexUInt, Revision } from '@vechain/sdk-core';
2+
import { JSONRPCInvalidDefaultBlock } from '@vechain/sdk-errors';
3+
4+
type DefaultBlock =
5+
| `0x${string}`
6+
| 'latest'
7+
| 'earliest'
8+
| 'pending'
9+
| 'safe'
10+
| 'finalized';
11+
const defaultBlockTags: DefaultBlock[] = [
12+
'latest',
13+
'earliest',
14+
'pending',
15+
'safe',
16+
'finalized'
17+
];
318

419
/**
5-
* Get the correct block number for the given block number.
6-
*
7-
* @param block - The block tag to get.
8-
* 'latest' or 'earliest' or 'pending' or 'safe' or 'finalized'
9-
* or an object: { blockNumber: number } or { blockHash: string }
20+
* Maps the Ethereum "default block" type to VeChainThor Revision type.
21+
* Ethereum "default block" can be:
22+
* - 'latest' or 'earliest' or 'pending' or 'safe' or 'finalized'
23+
* - a hexadecimal block number
24+
* VeChainThor revision type can be:
25+
* - 'best', 'next', 'justified', 'finalized'
26+
* - a hexadecimal block Id
27+
* - a integer block number
1028
*
11-
* @note
12-
* * Currently VeChainThor supports 'earliest', 'latest' and 'finalized' as block tags.
13-
* So 'pending' and 'safe' are converted to 'best' which is the alias for 'latest' and 'finalized' in VeChainThor.
29+
* @param defaultBlock - The Ethereum default block type to convert
30+
* @returns The VeChainThor revision type
1431
*/
15-
const getCorrectBlockNumberRPCToVeChain = (
16-
block: BlockQuantityInputRPC
17-
): string => {
18-
// Tag block number
19-
if (typeof block === 'string') {
20-
// Latest, Finalized, Safe blocks
21-
if (
22-
block === 'latest' ||
23-
block === 'finalized' ||
24-
block === 'safe' ||
25-
block === 'pending'
26-
)
27-
// 'best' is the alias for 'latest', 'finalized' and 'safe' in VeChainThor
28-
return 'best';
29-
30-
// Earliest block
31-
if (block === 'earliest') return Hex.of(0).toString();
32-
33-
// Hex number of block
34-
return block;
32+
const DefaultBlockToRevision = (defaultBlock: DefaultBlock): Revision => {
33+
// if valid hex then return integer block number
34+
if (HexUInt.isValid(defaultBlock)) {
35+
return Revision.of(HexUInt.of(defaultBlock).n.toString());
3536
}
36-
37-
// Object with block number
38-
if (block.blockNumber !== undefined) {
39-
return Hex.of(block.blockNumber).toString();
37+
// check if default block is a valid block tag
38+
if (!defaultBlockTags.includes(defaultBlock)) {
39+
const defaultBlockValue = defaultBlock.toString();
40+
throw new JSONRPCInvalidDefaultBlock(
41+
'DefaultBlockToRevision',
42+
`Invalid default block: ${defaultBlockValue}`,
43+
defaultBlockValue,
44+
null
45+
);
46+
}
47+
// map block tag to VeChainThor revision
48+
if (defaultBlock === 'earliest') {
49+
return Revision.of(HexUInt.of(0));
50+
} else if (defaultBlock === 'safe') {
51+
return Revision.of('justified');
52+
} else if (defaultBlock === 'finalized') {
53+
return Revision.of('finalized');
54+
} else {
55+
return Revision.of('best');
4056
}
41-
42-
// Object with block hash - Default case
43-
return block.blockHash;
4457
};
4558

46-
export { getCorrectBlockNumberRPCToVeChain };
59+
export { type DefaultBlock, DefaultBlockToRevision };
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
export * from './methods';
22
export * from './rpc-mapper';
3-
export type * from './types.d';

packages/network/src/provider/utils/rpc-mapper/methods/eth_call/eth_call.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import {
33
JSONRPCInvalidParams,
44
stringifyData
55
} from '@vechain/sdk-errors';
6-
import { getCorrectBlockNumberRPCToVeChain } from '../../../const';
6+
import { type DefaultBlock, DefaultBlockToRevision } from '../../../const';
77
import { type TransactionObjectInput } from './types';
8-
import { type BlockQuantityInputRPC } from '../../types';
98
import {
109
type SimulateTransactionClause,
1110
type SimulateTransactionOptions,
@@ -41,7 +40,7 @@ const ethCall = async (
4140
try {
4241
const [inputOptions, block] = params as [
4342
TransactionObjectInput,
44-
BlockQuantityInputRPC
43+
DefaultBlock
4544
];
4645

4746
// Simulate transaction
@@ -54,7 +53,7 @@ const ethCall = async (
5453
} satisfies SimulateTransactionClause
5554
],
5655
{
57-
revision: getCorrectBlockNumberRPCToVeChain(block),
56+
revision: DefaultBlockToRevision(block).toString(),
5857
gas:
5958
inputOptions.gas !== undefined
6059
? parseInt(inputOptions.gas, 16)

packages/network/src/provider/utils/rpc-mapper/methods/eth_estimateGas/eth_estimateGas.ts

+6-9
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import {
88
type SimulateTransactionClause,
99
type ThorClient
1010
} from '../../../../../thor-client';
11-
import { getCorrectBlockNumberRPCToVeChain } from '../../../const';
12-
import { type BlockQuantityInputRPC } from '../../types';
11+
import { type DefaultBlock, DefaultBlockToRevision } from '../../../const';
1312
import { RPC_DOCUMENTATION_URL } from '../../../../../utils';
1413

1514
/**
@@ -31,7 +30,7 @@ const ethEstimateGas = async (
3130
params: unknown[]
3231
): Promise<string> => {
3332
// Input validation
34-
if (![1, 2].includes(params.length) || typeof params[0] !== 'object')
33+
if (params.length !== 2 || typeof params[0] !== 'object')
3534
throw new JSONRPCInvalidParams(
3635
'eth_estimateGas',
3736
`Invalid input params for "eth_estimateGas" method. See ${RPC_DOCUMENTATION_URL} for details.`,
@@ -42,10 +41,11 @@ const ethEstimateGas = async (
4241
// NOTE: The standard requires block parameter.
4342
// Here it is ignored and can be added in the future compatibility reasons.
4443
// (INPUT CHECK TAKE CARE OF THIS)
45-
const [inputOptions, revision] = params as [
44+
const [inputOptions, defaultBlock] = params as [
4645
TransactionObjectInput,
47-
BlockQuantityInputRPC?
46+
DefaultBlock
4847
];
48+
const revision = DefaultBlockToRevision(defaultBlock);
4949

5050
const estimatedGas = await thorClient.gas.estimateGas(
5151
[
@@ -57,10 +57,7 @@ const ethEstimateGas = async (
5757
],
5858
inputOptions.from,
5959
{
60-
revision:
61-
revision !== undefined
62-
? getCorrectBlockNumberRPCToVeChain(revision)
63-
: undefined
60+
revision: revision.toString()
6461
}
6562
);
6663

packages/network/src/provider/utils/rpc-mapper/methods/eth_getBalance/eth_getBalance.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import {
44
JSONRPCInvalidParams,
55
stringifyData
66
} from '@vechain/sdk-errors';
7-
import type { BlockQuantityInputRPC } from '../../types';
8-
import { getCorrectBlockNumberRPCToVeChain } from '../../../const';
7+
import { type DefaultBlock, DefaultBlockToRevision } from '../../../const';
98
import { RPC_DOCUMENTATION_URL } from '../../../../../utils';
10-
import { Address, Revision } from '@vechain/sdk-core';
9+
import { Address } from '@vechain/sdk-core';
1110

1211
/**
1312
* RPC Method eth_getBalance implementation
@@ -40,13 +39,13 @@ const ethGetBalance = async (
4039
);
4140

4241
try {
43-
const [address, block] = params as [string, BlockQuantityInputRPC];
42+
const [address, block] = params as [string, DefaultBlock];
4443

4544
// Get the account details
4645
const accountDetails = await thorClient.accounts.getAccount(
4746
Address.of(address),
4847
{
49-
revision: Revision.of(getCorrectBlockNumberRPCToVeChain(block))
48+
revision: DefaultBlockToRevision(block)
5049
}
5150
);
5251

0 commit comments

Comments
 (0)