PHP WebShell

Текущая директория: /opt/BitGoJS/modules/utxo-lib/test/bitgo/psbt

Просмотр файла: fromHalfSigned.ts

import * as assert from 'assert';
import { describe, it } from 'mocha';

import { BIP32Interface, getNetworkName, Network, networks } from '../../../src';
import { outputScripts, PrevOutput, UtxoPsbt, UtxoTransaction } from '../../../src/bitgo';
import { getDefaultWalletKeys, getKeyName } from '../../../src/testutil';
import { getLeafHash } from '../../../src/bitgo/outputScripts';
import { getInputUpdate } from '../../../src/bitgo/psbt/fromHalfSigned';

import { getPrevOutputs, getTransactionStages } from '../../transaction_util';

import { readFixture } from '../../fixture.util';
import { normDefault } from '../../testutil/normalize';
import * as bs58check from 'bs58check';

function getScriptTypes2Of3() {
  // FIXME(BG-66941): p2trMusig2 signing does not work in this test suite yet
  //  because the test suite is written with TransactionBuilder
  return outputScripts.scriptTypes2Of3.filter((scriptType) => scriptType !== 'p2trMusig2');
}

function getScriptTypes(): outputScripts.ScriptType[] {
  return [...getScriptTypes2Of3(), 'p2shP2pk'];
}

const walletKeys = getDefaultWalletKeys();

function runTest(
  scriptType: outputScripts.ScriptType,
  signer: BIP32Interface,
  cosigner: BIP32Interface,
  network: Network
) {
  const signerName = getKeyName(walletKeys.triple, signer);
  const cosignerName = getKeyName(walletKeys.triple, cosigner);
  const networkName = getNetworkName(network);
  const signingKeys = [
    signerName === 'user' || cosignerName === 'user',
    signerName === 'backup' || cosignerName === 'backup',
    signerName === 'bitgo' || cosignerName === 'bitgo',
  ];
  describe(`UtxoPsbt ${[
    `scriptType=${scriptType}`,
    `network=${networkName}`,
    `signer=${signerName}`,
    `cosigner=${cosignerName}`,
  ].join(',')}`, function () {
    let prevOutputs: PrevOutput<bigint>[];
    let unsigned: UtxoTransaction<bigint>;
    let halfSigned: UtxoTransaction<bigint>;
    let fullSigned: UtxoTransaction<bigint>;
    before('create transaction', function () {
      prevOutputs = getPrevOutputs(scriptType, BigInt(1e8), network, {
        keys: walletKeys.triple,
        prevTx: (scriptType === 'p2sh' || scriptType === 'p2shP2pk') && getNetworkName(network) !== 'zcash',
      });
      ({ unsigned, halfSigned, fullSigned } = getTransactionStages(
        walletKeys.triple,
        signer,
        cosigner,
        scriptType,
        network,
        {
          amountType: 'bigint',
          outputAmount: BigInt(1e8),
          prevOutputs,
        }
      ));
    });

    function testGetInputUpdateForStage(stage: 'unsigned' | 'halfSigned') {
      it(`has getInputUpdate with expected value, stage=${stage}`, async function () {
        const tx = stage === 'unsigned' ? unsigned : halfSigned;
        const vin = 0;
        const inputUpdate = getInputUpdate(tx, vin, prevOutputs);
        assert.deepStrictEqual(
          normDefault(inputUpdate),
          await readFixture(
            `test/bitgo/fixtures/psbt/inputUpdate.${scriptType}.${stage}.${signerName}-${cosignerName}.json`,
            inputUpdate
          )
        );
      });
    }

    testGetInputUpdateForStage('unsigned');
    testGetInputUpdateForStage('halfSigned');

    it('has equal unsigned tx', function () {
      assert.strictEqual(
        UtxoPsbt.fromTransaction(unsigned, prevOutputs).getUnsignedTx().toBuffer().toString('hex'),
        unsigned.toBuffer().toString('hex')
      );

      if (scriptType !== 'p2shP2pk') {
        assert.strictEqual(
          UtxoPsbt.fromTransaction(halfSigned, prevOutputs).getUnsignedTx().toBuffer().toString('hex'),
          unsigned.toBuffer().toString('hex')
        );
      }
    });

    function signPsbt(startTx: UtxoTransaction<bigint>, signers: BIP32Interface[]) {
      const psbt = UtxoPsbt.fromTransaction(startTx, prevOutputs);
      psbt.updateGlobal({
        globalXpub: walletKeys.triple.map((bip32) => {
          const masterFingerprint = Buffer.alloc(4);
          masterFingerprint.writeUInt32BE(bip32.parentFingerprint);
          const extendedPubkey = bip32.neutered().toBase58();
          return {
            extendedPubkey: bs58check.decode(extendedPubkey),
            masterFingerprint,
            path: 'm',
          };
        }),
      });
      signers.forEach((s) => {
        if (scriptType === 'p2tr') {
          psbt.signTaprootInput(0, s, [
            getLeafHash({
              publicKeys: walletKeys.publicKeys,
              signer: signer.publicKey,
              cosigner: cosigner.publicKey,
            }),
          ]);
        } else {
          psbt.signAllInputs(s);
        }
      });
      assert.deepStrictEqual(psbt.getSignatureValidationArray(0, { rootNodes: walletKeys.triple }), signingKeys);
      psbt.finalizeAllInputs();
      return psbt.extractTransaction();
    }

    it('can go from unsigned to full-signed', function () {
      // TODO(BG-57748): inputs lack some required information
      this.skip();
      assert.deepStrictEqual(
        signPsbt(unsigned, [signer, cosigner]).toBuffer().toString('hex'),
        fullSigned.toBuffer().toString('hex')
      );
    });

    it('can go from half-signed to full-signed', function () {
      if (scriptType === 'p2shP2pk') {
        this.skip();
      }
      assert.deepStrictEqual(
        signPsbt(halfSigned, [cosigner]).toBuffer().toString('hex'),
        fullSigned.toBuffer().toString('hex')
      );
    });
  });
}

getScriptTypes().forEach((t) => {
  runTest(t, walletKeys.user, walletKeys.bitgo, networks.bitcoin);
  runTest(t, walletKeys.backup, walletKeys.user, networks.bitcoin);
});

Выполнить команду


Для локальной разработки. Не используйте в интернете!