@@ -9,8 +9,10 @@ import {
99 isNullInput ,
1010 readOutput ,
1111 TxOutput ,
12+ Psbt ,
1213} from '@scrypt-inc/bitcoinjs-lib' ;
1314import * as tools from 'uint8array-tools' ;
15+ import * as varuint from 'varuint-bitcoin' ;
1416import script_tests from './fixtures/scripts/script_tests.json' ;
1517import script_asset_tests from './fixtures/scripts/script_assets_test.json' ;
1618import tx_valid from './fixtures/scripts/tx_valid.json' ;
@@ -19,6 +21,10 @@ import { initEccLib } from '@scrypt-inc/bitcoinjs-lib';
1921import * as ecc from 'tiny-secp256k1' ;
2022import sinon from 'sinon' ;
2123
24+ import * as fs from 'fs' ;
25+ import { join } from 'path' ;
26+ import { cwd } from 'process' ;
27+
2228initEccLib ( ecc ) ;
2329
2430//the script string format used in bitcoind data tests
@@ -640,4 +646,76 @@ describe('Interpreter', () => {
640646
641647 testAllFixtures ( script_asset_tests as Array < any > ) ;
642648 } ) ;
649+
650+ describe ( 'psbt tests' , function ( ) {
651+ const psbtBase64 = fs
652+ . readFileSync ( join ( cwd ( ) , 'test' , 'fixtures' , 'psbt' , '0.txt' ) )
653+ . toString ( ) ;
654+
655+ const psbt = Psbt . fromBase64 ( psbtBase64 ) ;
656+
657+ assert . strictEqual ( bvmVerify ( psbt , 0 ) , true ) ;
658+ assert . strictEqual ( bvmVerify ( psbt , 1 ) , true ) ;
659+ } ) ;
643660} ) ;
661+
662+ function bvmVerify ( extPsbt : Psbt , inputIndex : number = 0 ) : true | string {
663+ const prevOuts = extPsbt . data . inputs . map ( input => input . witnessUtxo ! ) ;
664+
665+ const interp = new Interpreter ( ) ;
666+ const prevScript = prevOuts [ inputIndex ] . script ;
667+ const prevSatoshi = Number ( prevOuts [ inputIndex ] . value ) ;
668+
669+ const finalScriptWitness =
670+ extPsbt . data . inputs [ inputIndex ] . finalScriptWitness || Uint8Array . from ( [ ] ) ;
671+
672+ const witness : Uint8Array [ ] = scriptWitnessToWitnessStack ( finalScriptWitness ) ;
673+
674+ const flags =
675+ Interpreter . SCRIPT_VERIFY_TAPROOT |
676+ Interpreter . SCRIPT_VERIFY_WITNESS |
677+ Interpreter . SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
678+ Interpreter . SCRIPT_VERIFY_CHECKSEQUENCEVERIFY ;
679+ const ret = interp . verify (
680+ new Uint8Array ( 0 ) ,
681+ prevScript ,
682+ extPsbt . extractTransaction ( ) ,
683+ inputIndex ,
684+ flags ,
685+ witness ,
686+ prevSatoshi ,
687+ prevOuts ,
688+ ) ;
689+ if ( ! ret ) {
690+ return interp . getErr ( ) ;
691+ }
692+
693+ return true ;
694+ }
695+
696+ function scriptWitnessToWitnessStack ( scriptWitness : Uint8Array ) {
697+ const witness : Uint8Array [ ] = [ ] ;
698+ function readSlice ( buffer : Uint8Array , offset : number , len : number ) {
699+ return buffer . slice ( offset , offset + len ) ;
700+ }
701+ function readVarInt ( buffer : Uint8Array , offset : number ) {
702+ return varuint . decode ( buffer , offset ) ;
703+ }
704+ function readVarSlice ( buffer : Uint8Array , offset : number ) {
705+ const { numberValue, bytes } = readVarInt ( buffer , offset ) ;
706+ const slice = readSlice ( buffer , offset + bytes , numberValue ! ) ;
707+ return { slice, bytes : bytes + numberValue ! } ;
708+ }
709+
710+ let offset = 0 ;
711+ const { numberValue, bytes } = readVarInt ( scriptWitness , offset ) ;
712+
713+ offset += bytes ;
714+ for ( let i = 0 ; i < numberValue ! ; i ++ ) {
715+ const { slice, bytes } = readVarSlice ( scriptWitness , offset ) ;
716+ witness . push ( slice ) ;
717+ offset += bytes ;
718+ }
719+
720+ return witness ;
721+ }
0 commit comments