@@ -27,49 +27,130 @@ chai.use(solidity);
2727import { ethers } from 'ethers' ;
2828import Assertions from '../../helpers/assertions' ;
2929import { predefined } from '@hashgraph/json-rpc-relay' ;
30+ import { AliasAccount } from '../../clients/servicesClient' ;
31+ import { numberTo0x } from '../../../../../packages/relay/src/formatters' ;
32+ import RelayCall from '../../../tests/helpers/constants' ;
33+ import { Utils } from '../../helpers/utils' ;
34+ import e from 'express' ;
3035const WS_RELAY_URL = `${ process . env . WS_RELAY_URL } ` ;
3136
32- const createSubscription = ( ws , subscriptionId ) => {
33- return new Promise ( ( resolve , reject ) => {
34- ws . on ( 'message' , function incoming ( data ) {
35- const response = JSON . parse ( data ) ;
36- if ( response . id === subscriptionId && response . result ) {
37- console . log ( `Subscription ${ subscriptionId } successful with ID: ${ response . result } ` ) ;
38- resolve ( response . result ) ; // Resolve with the subscription ID
39- } else if ( response . method === 'eth_subscription' ) {
40- console . log ( `Subscription ${ subscriptionId } received block:` , response . params . result ) ;
41- // You can add more logic here to handle incoming blocks
42- }
43- } ) ;
37+ const ethAddressRegex = / ^ 0 x [ a - f A - F 0 - 9 ] * $ / ;
4438
45- ws . on ( 'open' , function open ( ) {
46- ws . send (
47- JSON . stringify ( {
48- id : subscriptionId ,
49- jsonrpc : '2.0' ,
50- method : 'eth_subscribe' ,
51- params : [ 'newHeads' ] ,
52- } ) ,
53- ) ;
54- } ) ;
39+ async function sendTransaction (
40+ ONE_TINYBAR : any ,
41+ CHAIN_ID : string | number ,
42+ accounts : AliasAccount [ ] ,
43+ rpcServer : any ,
44+ requestId : any ,
45+ mirrorNodeServer : any ,
46+ ) {
47+ const transaction = {
48+ value : ONE_TINYBAR ,
49+ gasLimit : numberTo0x ( 30000 ) ,
50+ chainId : Number ( CHAIN_ID ) ,
51+ to : accounts [ 1 ] . address ,
52+ nonce : await rpcServer . getAccountNonce ( accounts [ 0 ] . address , requestId ) ,
53+ maxFeePerGas : await rpcServer . gasPrice ( requestId ) ,
54+ } ;
5555
56- ws . on ( 'error' , ( error ) => {
57- reject ( error ) ;
58- } ) ;
59- } ) ;
60- } ;
56+ const signedTx = await accounts [ 0 ] . wallet . signTransaction ( transaction ) ;
57+ const transactionHash = await rpcServer . sendRawTransaction ( signedTx , requestId ) ;
58+
59+ await mirrorNodeServer . get ( `/contracts/results/${ transactionHash } ` , requestId ) ;
60+
61+ return await rpcServer . call ( RelayCall . ETH_ENDPOINTS . ETH_GET_TRANSACTION_RECEIPT , [ transactionHash ] , requestId ) ;
62+ }
63+
64+ function verifyResponse ( response : any , done : Mocha . Done , webSocket : any , includeTransactions : boolean ) {
65+ if ( response ?. params ?. result ?. transactions ?. length > 0 ) {
66+ try {
67+ expect ( response ) . to . have . property ( 'jsonrpc' , '2.0' ) ;
68+ expect ( response ) . to . have . property ( 'method' , 'eth_subscription' ) ;
69+ expect ( response ) . to . have . property ( 'params' ) ;
70+ expect ( response . params ) . to . have . property ( 'result' ) ;
71+ expect ( response . params . result ) . to . have . property ( 'difficulty' ) ;
72+ expect ( response . params . result ) . to . have . property ( 'extraData' ) ;
73+ expect ( response . params . result ) . to . have . property ( 'gasLimit' ) ;
74+ expect ( response . params . result ) . to . have . property ( 'gasUsed' ) ;
75+ expect ( response . params . result ) . to . have . property ( 'logsBloom' ) ;
76+ expect ( response . params . result ) . to . have . property ( 'miner' ) ;
77+ expect ( response . params . result ) . to . have . property ( 'nonce' ) ;
78+ expect ( response . params . result ) . to . have . property ( 'number' ) ;
79+ expect ( response . params . result ) . to . have . property ( 'parentHash' ) ;
80+ expect ( response . params . result ) . to . have . property ( 'receiptsRoot' ) ;
81+ expect ( response . params . result ) . to . have . property ( 'sha3Uncles' ) ;
82+ expect ( response . params . result ) . to . have . property ( 'stateRoot' ) ;
83+ expect ( response . params . result ) . to . have . property ( 'timestamp' ) ;
84+ expect ( response . params . result ) . to . have . property ( 'transactionsRoot' ) ;
85+ expect ( response . params . result ) . to . have . property ( 'hash' ) ;
86+ expect ( response . params ) . to . have . property ( 'subscription' ) ;
87+
88+ if ( includeTransactions ) {
89+ expect ( response . params . result ) . to . have . property ( 'transactions' ) ;
90+ expect ( response . params . result . transactions ) . to . have . lengthOf ( 1 ) ;
91+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'hash' ) ;
92+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'nonce' ) ;
93+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'blockHash' ) ;
94+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'blockNumber' ) ;
95+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'transactionIndex' ) ;
96+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'from' ) ;
97+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'to' ) ;
98+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'value' ) ;
99+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'gas' ) ;
100+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'gasPrice' ) ;
101+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'input' ) ;
102+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'v' ) ;
103+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'r' ) ;
104+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 's' ) ;
105+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'type' ) ;
106+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'maxFeePerGas' ) ;
107+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'maxPriorityFeePerGas' ) ;
108+ expect ( response . params . result . transactions [ 0 ] ) . to . have . property ( 'chainId' ) ;
109+ } else {
110+ expect ( response . params . result ) . to . have . property ( 'transactions' ) ;
111+ expect ( response . params . result . transactions ) . to . have . lengthOf ( 1 ) ;
112+ expect ( response . params . result . transactions [ 0 ] ) . to . match ( ethAddressRegex ) ;
113+ }
114+ done ( ) ;
115+ } catch ( error ) {
116+ webSocket . close ( ) ;
117+ done ( error ) ;
118+ }
119+ }
120+ }
61121
62122describe ( '@web-socket Acceptance Tests' , async function ( ) {
63123 this . timeout ( 240 * 1000 ) ; // 240 seconds
124+ const accounts : AliasAccount [ ] = [ ] ;
125+ const CHAIN_ID = process . env . CHAIN_ID || 0 ;
126+ const ONE_TINYBAR = Utils . add0xPrefix ( Utils . toHex ( ethers . parseUnits ( '1' , 10 ) ) ) ;
64127
65- let server ;
128+ const defaultGasPrice = numberTo0x ( Assertions . defaultGasPrice ) ;
129+ const defaultGasLimit = numberTo0x ( 3_000_000 ) ;
130+
131+ const defaultTransaction = {
132+ value : ONE_TINYBAR ,
133+ chainId : Number ( CHAIN_ID ) ,
134+ maxPriorityFeePerGas : defaultGasPrice ,
135+ maxFeePerGas : defaultGasPrice ,
136+ gasLimit : defaultGasLimit ,
137+ type : 2 ,
138+ } ;
139+
140+ let mirrorNodeServer , requestId , rpcServer , wsServer ;
66141
67142 let wsProvider ;
68143 let originalWsNewHeadsEnabledValue , originalWsSubcriptionLimitValue ;
69144
70145 before ( async ( ) => {
71- const { socketServer } = global ;
72- server = socketServer ;
146+ // @ts -ignore
147+ const { servicesNode, socketServer, mirrorNode, relay, logger } = global ;
148+ mirrorNodeServer = mirrorNode ;
149+ rpcServer = relay ;
150+ wsServer = socketServer ;
151+
152+ accounts [ 0 ] = await servicesNode . createAliasAccount ( 100 , relay . provider , requestId ) ;
153+ accounts [ 1 ] = await servicesNode . createAliasAccount ( 5 , relay . provider , requestId ) ;
73154
74155 // cache original ENV values
75156 originalWsNewHeadsEnabledValue = process . env . WS_NEW_HEADS_ENABLED ;
@@ -83,15 +164,13 @@ describe('@web-socket Acceptance Tests', async function () {
83164
84165 wsProvider = await new ethers . WebSocketProvider ( WS_RELAY_URL ) ;
85166 await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
86- if ( server ) expect ( server . _connections ) . to . equal ( 1 ) ;
87167 } ) ;
88168
89169 afterEach ( async ( ) => {
90170 if ( wsProvider ) {
91171 await wsProvider . destroy ( ) ;
92172 await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
93173 }
94- if ( server ) expect ( server . _connections ) . to . equal ( 0 ) ;
95174 process . env . WS_SUBSCRIPTION_LIMIT = originalWsSubcriptionLimitValue ;
96175 } ) ;
97176
@@ -150,4 +229,96 @@ describe('@web-socket Acceptance Tests', async function () {
150229 await new Promise ( ( resolve ) => setTimeout ( resolve , 500 ) ) ;
151230 } ) ;
152231 } ) ;
232+
233+ describe ( 'Subscriptions for newHeads' , async function ( ) {
234+ it ( 'should subscribe to newHeads, include transactions true, and receive a valid JSON RPC response' , ( done ) => {
235+ process . env . WS_NEW_HEADS_ENABLED = 'true' ;
236+ const webSocket = new WebSocket ( WS_RELAY_URL ) ;
237+ const subscriptionId = 1 ;
238+ webSocket . on ( 'open' , function open ( ) {
239+ webSocket . send (
240+ JSON . stringify ( {
241+ id : subscriptionId ,
242+ jsonrpc : '2.0' ,
243+ method : 'eth_subscribe' ,
244+ params : [ 'newHeads' , { includeTransactions : true } ] ,
245+ } ) ,
246+ ) ;
247+ } ) ;
248+
249+ let responseCounter = 0 ;
250+
251+ sendTransaction ( ONE_TINYBAR , CHAIN_ID , accounts , rpcServer , requestId , mirrorNodeServer ) ;
252+ webSocket . on ( 'message' , function incoming ( data ) {
253+ const response = JSON . parse ( data ) ;
254+
255+ responseCounter ++ ;
256+ verifyResponse ( response , done , webSocket , true ) ;
257+ if ( responseCounter > 1 ) {
258+ webSocket . close ( ) ;
259+ done ( ) ;
260+ }
261+ } ) ;
262+ } ) ;
263+
264+ it ( 'should subscribe to newHeads, without the "include transactions", and receive a valid JSON RPC response' , ( done ) => {
265+ process . env . WS_NEW_HEADS_ENABLED = 'true' ;
266+ const webSocket = new WebSocket ( WS_RELAY_URL ) ;
267+ const subscriptionId = 1 ;
268+ webSocket . on ( 'open' , function open ( ) {
269+ webSocket . send (
270+ JSON . stringify ( {
271+ id : subscriptionId ,
272+ jsonrpc : '2.0' ,
273+ method : 'eth_subscribe' ,
274+ params : [ 'newHeads' ] ,
275+ } ) ,
276+ ) ;
277+ } ) ;
278+
279+ let responseCounter = 0 ;
280+
281+ sendTransaction ( ONE_TINYBAR , CHAIN_ID , accounts , rpcServer , requestId , mirrorNodeServer ) ;
282+ webSocket . on ( 'message' , function incoming ( data ) {
283+ const response = JSON . parse ( data ) ;
284+
285+ responseCounter ++ ;
286+ verifyResponse ( response , done , webSocket , false ) ;
287+ if ( responseCounter > 1 ) {
288+ webSocket . close ( ) ;
289+ done ( ) ;
290+ }
291+ } ) ;
292+ } ) ;
293+
294+ it ( 'should subscribe to newHeads, with "include transactions false", and receive a valid JSON RPC response' , ( done ) => {
295+ process . env . WS_NEW_HEADS_ENABLED = 'true' ;
296+ const webSocket = new WebSocket ( WS_RELAY_URL ) ;
297+ const subscriptionId = 1 ;
298+ webSocket . on ( 'open' , function open ( ) {
299+ webSocket . send (
300+ JSON . stringify ( {
301+ id : subscriptionId ,
302+ jsonrpc : '2.0' ,
303+ method : 'eth_subscribe' ,
304+ params : [ 'newHeads' , { includeTransactions : false } ] ,
305+ } ) ,
306+ ) ;
307+ } ) ;
308+
309+ let responseCounter = 0 ;
310+
311+ sendTransaction ( ONE_TINYBAR , CHAIN_ID , accounts , rpcServer , requestId , mirrorNodeServer ) ;
312+ webSocket . on ( 'message' , function incoming ( data ) {
313+ const response = JSON . parse ( data ) ;
314+
315+ responseCounter ++ ;
316+ verifyResponse ( response , done , webSocket , false ) ;
317+ if ( responseCounter > 1 ) {
318+ webSocket . close ( ) ;
319+ done ( ) ;
320+ }
321+ } ) ;
322+ } ) ;
323+ } ) ;
153324} ) ;
0 commit comments