@@ -17,6 +17,8 @@ import {
1717 isUnlockableUtxo ,
1818 isStandardUnlockableUtxo ,
1919 StandardUnlockableUtxo ,
20+ VmResourceUsage ,
21+ isContractUnlocker ,
2022} from './interfaces.js' ;
2123import { NetworkProvider } from './network/index.js' ;
2224import {
@@ -172,6 +174,44 @@ export class TransactionBuilder {
172174 return debugLibauthTemplate ( this . getLibauthTemplate ( ) , this ) ;
173175 }
174176
177+ getVmResourceUsage ( verbose : boolean = false ) : Array < VmResourceUsage > {
178+ // Note that only StandardUnlockableUtxo inputs are supported for debugging, so any transaction with custom unlockers
179+ // cannot be debugged (and therefore cannot return VM resource usage)
180+ const results = this . debug ( ) ;
181+ const vmResourceUsage : Array < VmResourceUsage > = [ ] ;
182+ const tableData : Array < Record < string , any > > = [ ] ;
183+
184+ const formatMetric = ( value : number , total : number , withPercentage : boolean = false ) : string =>
185+ `${ formatNumber ( value ) } / ${ formatNumber ( total ) } ${ withPercentage ? ` (${ ( value / total * 100 ) . toFixed ( 0 ) } %)` : '' } ` ;
186+ const formatNumber = ( value : number ) : string => value . toLocaleString ( 'en' ) ;
187+
188+ const resultEntries = Object . entries ( results ) ;
189+ for ( const [ index , input ] of this . inputs . entries ( ) ) {
190+ const [ , result ] = resultEntries . find ( ( [ entryKey ] ) => entryKey . includes ( `input${ index } ` ) ) ?? [ ] ;
191+ const metrics = result ?. at ( - 1 ) ?. metrics ;
192+
193+ // Should not happen
194+ if ( ! metrics ) throw new Error ( 'VM resource could not be calculated' ) ;
195+
196+ vmResourceUsage . push ( metrics ) ;
197+ tableData . push ( {
198+ 'Contract - Function' : isContractUnlocker ( input . unlocker ) ? `${ input . unlocker . contract . name } - ${ input . unlocker . abiFunction . name } ` : 'P2PKH Input' ,
199+ Ops : metrics . evaluatedInstructionCount ,
200+ 'Op Cost Budget Usage' : formatMetric ( metrics . operationCost , metrics . maximumOperationCost , true ) ,
201+ SigChecks : formatMetric ( metrics . signatureCheckCount , metrics . maximumSignatureCheckCount ) ,
202+ Hashes : formatMetric ( metrics . hashDigestIterations , metrics . maximumHashDigestIterations ) ,
203+ } ) ;
204+ }
205+
206+ if ( verbose ) {
207+ console . log ( 'VM Resource usage by inputs:' ) ;
208+ console . table ( tableData ) ;
209+ }
210+
211+ return vmResourceUsage ;
212+ }
213+
214+ // TODO: rename to getBitauthUri()
175215 bitauthUri ( ) : string {
176216 console . warn ( 'WARNING: it is unsafe to use this Bitauth URI when using real private keys as they are included in the transaction template' ) ;
177217 return getBitauthUri ( this . getLibauthTemplate ( ) ) ;
0 commit comments