PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-staking/test/unit/coreDao
Просмотр файла: descriptor.ts
import * as assert from 'assert';
import * as utxolib from '@bitgo/utxo-lib';
import { Descriptor } from '@bitgo/wasm-miniscript';
import { getFixture } from '@bitgo/utxo-core/testutil';
import { createMultiSigDescriptor, decodeTimelock } from '../../../src/coreDao';
import { finalizePsbt, updateInputWithDescriptor } from './utils';
describe('descriptor', function () {
const baseFixturePath = 'test/fixtures/coreDao/descriptor/';
const rootWalletKeys = utxolib.testutil.getDefaultWalletKeys();
const key1 = rootWalletKeys.triple[0];
const key2 = rootWalletKeys.triple[1];
const key3 = rootWalletKeys.triple[2];
const validLocktime = 2048;
it('should fail if m is longer than the number of keys or not at least 1', function () {
assert.throws(() => {
createMultiSigDescriptor('sh', validLocktime, 3, [key1, key2], false);
});
assert.throws(() => {
createMultiSigDescriptor('sh', validLocktime, 0, [key1, key2], false);
});
});
it('should fail if locktime is invalid', function () {
assert.throws(() => {
createMultiSigDescriptor('sh', 0, 2, [key1, key2], false);
});
});
async function runTestForParams(scriptType: 'sh' | 'sh-wsh' | 'wsh', m: number, keys: utxolib.BIP32Interface[]) {
const fixturePath = baseFixturePath + `${scriptType}-${m}of${keys.length}`;
describe(`should create a ${m} of ${keys.length} multi-sig ${scriptType} descriptor`, function () {
it('has expected descriptor string', async function () {
const descriptorString = createMultiSigDescriptor(scriptType, validLocktime, m, keys, false);
assert.strictEqual(
descriptorString,
await getFixture(fixturePath + `-string.txt`, descriptorString),
descriptorString
);
});
it('has expected AST', async function () {
const descriptor = Descriptor.fromString(
createMultiSigDescriptor(scriptType, validLocktime, m, keys, false),
'derivable'
);
assert.deepStrictEqual(descriptor.node(), await getFixture(fixturePath + '-ast.json', descriptor.node()));
});
it('has expected asm', async function () {
const descriptor = Descriptor.fromString(
createMultiSigDescriptor(scriptType, validLocktime, m, keys, false),
'derivable'
);
const asmString = descriptor.atDerivationIndex(0).toAsmString();
assert.strictEqual(asmString, await getFixture(fixturePath + '-asm.txt', asmString), asmString);
});
it('can be signed', async function () {
// Derive the script from the descriptor
const descriptor = Descriptor.fromString(
createMultiSigDescriptor(scriptType, validLocktime, m, keys, false),
'derivable'
);
const descriptorAt0 = descriptor.atDerivationIndex(0);
const script = Buffer.from(descriptorAt0.scriptPubkey());
// Make the prevTx
const prevPsbt = utxolib.testutil.constructPsbt(
[{ scriptType: 'p2wsh', value: BigInt(1.1e8) }],
[{ script: script.toString('hex'), value: BigInt(1e8) }],
utxolib.networks.bitcoin,
rootWalletKeys,
'fullsigned'
);
const prevTx = prevPsbt.finalizeAllInputs().extractTransaction();
// Create the PSBT and sign
const psbt = Object.assign(new utxolib.Psbt({ network: utxolib.networks.bitcoin }), {
locktime: validLocktime,
});
psbt.addInput({
hash: prevTx.getId(),
index: 0,
sequence: 0xfffffffe,
});
if (scriptType === 'sh-wsh') {
psbt.updateInput(0, { witnessUtxo: { script, value: BigInt(1e8) } });
} else {
psbt.updateInput(0, { nonWitnessUtxo: prevTx.toBuffer() });
}
psbt.addOutput({ script, value: BigInt(0.9e8) });
updateInputWithDescriptor(psbt, 0, descriptorAt0);
keys.forEach((signer, i) => {
if (i >= m) {
return;
}
psbt.signAllInputsHD(signer);
});
// Get the fully signed transaction and check
const signedTx = finalizePsbt(psbt).extractTransaction().toBuffer();
assert.strictEqual(
signedTx.toString('hex'),
await getFixture(fixturePath + '-tx.txt', signedTx.toString('hex'))
);
});
});
}
runTestForParams('sh', 2, [key1, key2]);
runTestForParams('sh-wsh', 2, [key1, key2]);
runTestForParams('sh', 3, [key1, key2, key3]);
runTestForParams('wsh', 3, [key1, key2, key3]);
it('should recreate the script used in testnet staking transaction', function () {
// Source: https://mempool.space/testnet/address/2MxTi2EhHKgdJFKRTBttVGGxir9ZzjmKCXw
// 2 of 2 multisig
const timelock = 'fce4cb66';
const pubkey1 = '03ecb6d4b7f5d56962e547fc52dd588359f5729c0ba856d6978b84723895a16691';
const pubkey2 = '024aaea25d82b1db2be030a05b641d6302e48ed652b1ca9cb08a67267fcbb56747';
const redeemScriptASM = [
'OP_PUSHBYTES_4',
timelock,
'OP_CLTV',
'OP_DROP',
'OP_PUSHNUM_2',
'OP_PUSHBYTES_33',
pubkey1,
'OP_PUSHBYTES_33',
pubkey2,
'OP_PUSHNUM_2',
'OP_CHECKMULTISIG',
].join(' ');
const decodedTimelock = decodeTimelock(Buffer.from(timelock, 'hex'));
const descriptor = createMultiSigDescriptor(
'sh',
decodedTimelock,
2,
[Buffer.from(pubkey1, 'hex'), Buffer.from(pubkey2, 'hex')],
false
);
const descriptorASM = Descriptor.fromString(descriptor, 'definite').toAsmString();
assert.deepStrictEqual(redeemScriptASM, descriptorASM);
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!