testmempool accept more validation & switch to JSON array format
This commit is contained in:
		
							parent
							
								
									f3232b2d5c
								
							
						
					
					
						commit
						2a43255802
					
				| @ -751,13 +751,13 @@ class BitcoinRoutes { | ||||
|   } | ||||
| 
 | ||||
|   private async $testTransactions(req: Request, res: Response) { | ||||
|     res.setHeader('content-type', 'text/plain'); | ||||
|     try { | ||||
|       const rawTxs = Common.getTransactionsFromRequest(req); | ||||
|       const maxfeerate = parseFloat(req.query.maxfeerate as string); | ||||
|       const result = await bitcoinApi.$testMempoolAccept(rawTxs, maxfeerate); | ||||
|       res.send(result); | ||||
|     } catch (e: any) { | ||||
|       res.setHeader('content-type', 'text/plain'); | ||||
|       res.status(400).send(e.message && e.code ? 'testmempoolaccept RPC error: ' + JSON.stringify({ code: e.code, message: e.message }) | ||||
|         : (e.message || 'Error')); | ||||
|     } | ||||
|  | ||||
| @ -946,12 +946,16 @@ export class Common { | ||||
|     return this.validateTransactionHex(matches[1].toLowerCase()); | ||||
|   } | ||||
| 
 | ||||
|   static getTransactionsFromRequest(req: Request): string[] { | ||||
|     if (typeof req.body !== 'string') { | ||||
|       throw Object.assign(new Error('Non-string request body'), { code: -1 }); | ||||
|   static getTransactionsFromRequest(req: Request, limit: number = 25): string[] { | ||||
|     if (!Array.isArray(req.body) || req.body.some(hex => typeof hex !== 'string')) { | ||||
|       throw Object.assign(new Error('Invalid request body (should be an array of hexadecimal strings)'), { code: -1 }); | ||||
|     } | ||||
| 
 | ||||
|     const txs = req.body.split(','); | ||||
|     if (limit && req.body.length > limit) { | ||||
|       throw Object.assign(new Error('Exceeded maximum of 25 transactions'), { code: -1 }); | ||||
|     } | ||||
| 
 | ||||
|     const txs = req.body; | ||||
| 
 | ||||
|     return txs.map(rawTx => { | ||||
|       // Support both upper and lower case hex
 | ||||
|  | ||||
| @ -131,6 +131,7 @@ class Server { | ||||
|       }) | ||||
|       .use(express.urlencoded({ extended: true })) | ||||
|       .use(express.text({ type: ['text/plain', 'application/base64'] })) | ||||
|       .use(express.json()) | ||||
|       ; | ||||
| 
 | ||||
|     if (config.DATABASE.ENABLED && config.FIAT_PRICE.ENABLED) { | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
|   td, th { | ||||
|     &.allowed { | ||||
|       width: 10%; | ||||
|       text-align: center; | ||||
|     } | ||||
|     &.txid { | ||||
|       width: 50%; | ||||
|  | ||||
| @ -37,6 +37,21 @@ export class TestTransactionsComponent implements OnInit { | ||||
|   } | ||||
| 
 | ||||
|   testTxs() { | ||||
|     let txs: string[] = []; | ||||
|     try { | ||||
|       txs = (this.testTxsForm.get('txs')?.value as string).split(',').map(hex => hex.trim()); | ||||
|       if (!txs?.length) { | ||||
|         this.error = 'At least one transaction is required'; | ||||
|         return; | ||||
|       } else if (txs.length > 25) { | ||||
|         this.error = 'Exceeded maximum of 25 transactions'; | ||||
|         return; | ||||
|       } | ||||
|     } catch (e) { | ||||
|       this.error = e?.message; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     let maxfeerate; | ||||
|     this.invalidMaxfeerate = false; | ||||
|     try { | ||||
| @ -51,7 +66,7 @@ export class TestTransactionsComponent implements OnInit { | ||||
|     this.isLoading = true; | ||||
|     this.error = ''; | ||||
|     this.results = []; | ||||
|     this.apiService.testTransactions$((this.testTxsForm.get('txs')?.value as string).split(',').map(hex => hex.trim()).join(','), maxfeerate === 0.1 ? null : maxfeerate) | ||||
|     this.apiService.testTransactions$(txs, maxfeerate === 0.1 ? null : maxfeerate) | ||||
|       .subscribe((result) => { | ||||
|         this.isLoading = false; | ||||
|         this.results = result || []; | ||||
|  | ||||
| @ -238,8 +238,8 @@ export class ApiService { | ||||
|     return this.httpClient.post<any>(this.apiBaseUrl + this.apiBasePath + '/api/tx', hexPayload, { responseType: 'text' as 'json'}); | ||||
|   } | ||||
| 
 | ||||
|   testTransactions$(hexPayload: string, maxfeerate?: number): Observable<TestMempoolAcceptResult[]> { | ||||
|     return this.httpClient.post<TestMempoolAcceptResult[]>(this.apiBaseUrl + this.apiBasePath + `/api/txs/test${maxfeerate != null ? '?maxfeerate=' + maxfeerate.toFixed(8) : ''}`, hexPayload); | ||||
|   testTransactions$(rawTxs: string[], maxfeerate?: number): Observable<TestMempoolAcceptResult[]> { | ||||
|     return this.httpClient.post<TestMempoolAcceptResult[]>(this.apiBaseUrl + this.apiBasePath + `/api/txs/test${maxfeerate != null ? '?maxfeerate=' + maxfeerate.toFixed(8) : ''}`, rawTxs); | ||||
|   } | ||||
| 
 | ||||
|   getTransactionStatus$(txid: string): Observable<any> { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user