PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-lib/src/bitgo/zcash
Просмотр файла: ZcashPsbt.ts
import { PsbtOpts, UtxoPsbt } from '../UtxoPsbt';
import {
getDefaultConsensusBranchIdForVersion,
getDefaultVersionGroupIdForVersion,
ZcashTransaction,
} from './ZcashTransaction';
import { Network, PsbtTransaction, Signer } from '../../';
import { Psbt as PsbtBase } from 'bip174';
import * as types from 'bitcoinjs-lib/src/types';
import { ValidateSigFunction } from 'bitcoinjs-lib/src/psbt';
import { ProprietaryKeySubtype, PSBT_PROPRIETARY_IDENTIFIER, withUnsafeNonSegwit } from '../PsbtUtil';
const typeforce = require('typeforce');
const CONSENSUS_BRANCH_ID_KEY = Buffer.concat([
Buffer.of(0xfc),
Buffer.of(0x05),
Buffer.from(PSBT_PROPRIETARY_IDENTIFIER),
Buffer.of(ProprietaryKeySubtype.ZEC_CONSENSUS_BRANCH_ID),
]);
export class ZcashPsbt extends UtxoPsbt<ZcashTransaction<bigint>> {
protected static transactionFromBuffer(buffer: Buffer, network: Network): ZcashTransaction<bigint> {
return ZcashTransaction.fromBuffer<bigint>(buffer, false, 'bigint', network);
}
static createPsbt(opts: PsbtOpts, data?: PsbtBase): ZcashPsbt {
return new ZcashPsbt(
opts,
data || new PsbtBase(new PsbtTransaction({ tx: new ZcashTransaction<bigint>(opts.network) }))
);
}
/**
* In version < 5 of Zcash transactions, the consensus branch ID is not serialized in the transaction
* whereas in version 5 it is. If the transaction is less than a version 5, set the consensus branch id
* in the global map in the psbt. If it is a version 5 transaction, throw an error if the consensus
* branch id is set in the psbt (because it should be on the transaction already).
* @param buffer Psbt buffer
* @param opts options
*/
static fromBuffer(buffer: Buffer, opts: PsbtOpts): UtxoPsbt<ZcashTransaction<bigint>> {
const psbt = super.fromBuffer(buffer, opts) as ZcashPsbt;
// Read `consensusBranchId` from the global-map
let consensusBranchId: number | undefined = undefined;
psbt.data.globalMap.unknownKeyVals?.forEach(({ key, value }, i) => {
if (key.equals(CONSENSUS_BRANCH_ID_KEY)) {
consensusBranchId = value.readUint32LE();
}
});
switch (psbt.tx.version) {
case 4:
case ZcashTransaction.VERSION4_BRANCH_CANOPY:
case ZcashTransaction.VERSION4_BRANCH_NU5:
if (!consensusBranchId || !psbt.data.globalMap.unknownKeyVals) {
throw new Error('Could not find consensus branch id on psbt for version 4 Zcash transaction');
}
psbt.tx.consensusBranchId = consensusBranchId;
psbt.data.globalMap.unknownKeyVals = psbt.data.globalMap.unknownKeyVals.filter(
({ key }) => key !== CONSENSUS_BRANCH_ID_KEY
);
// Delete consensusBranchId from globalMap so that if we were to serialize the psbt again
// we would not add a duplicate key into the global map
psbt.data.globalMap.unknownKeyVals.pop();
return psbt;
case 5:
case ZcashTransaction.VERSION5_BRANCH_NU5:
if (consensusBranchId) {
throw new Error('Found consensus branch id in psbt global-map for version 5 Zcash transaction');
}
return psbt;
default:
throw new Error(`Unsupported transaction version ${psbt.tx.version}`);
}
}
/**
* If it is a version 4 transaction, add the consensus branch id to
* the global map. If it is a version 5 transaction, just return the
* buffer because the consensus branch id is already serialized in
* the transaction.
*/
toBuffer(): Buffer {
if (this.tx.version === 5 || this.tx.version >= ZcashTransaction.VERSION5_BRANCH_NU5) {
return super.toBuffer();
}
const value = Buffer.alloc(4);
value.writeUint32LE(this.tx.consensusBranchId);
this.addUnknownKeyValToGlobal({ key: CONSENSUS_BRANCH_ID_KEY, value });
if (!this.data.globalMap.unknownKeyVals) {
throw new Error('Failed adding consensus branch id to unknownKeyVals');
}
const buff = super.toBuffer();
this.data.globalMap.unknownKeyVals.pop();
return buff;
}
setVersion(version: number, overwinter = true): this {
typeforce(types.UInt32, version);
this.tx.overwintered = overwinter ? 1 : 0;
this.tx.version = version;
return this;
}
setDefaultsForVersion(network: Network, version: number): void {
switch (version) {
case 4:
case ZcashTransaction.VERSION4_BRANCH_CANOPY:
case ZcashTransaction.VERSION4_BRANCH_NU5:
case ZcashTransaction.VERSION4_BRANCH_NU6:
this.setVersion(4);
break;
case 5:
case ZcashTransaction.VERSION5_BRANCH_NU5:
case ZcashTransaction.VERSION5_BRANCH_NU6:
this.setVersion(5);
break;
default:
throw new Error(`invalid version ${version}`);
}
this.tx.versionGroupId = getDefaultVersionGroupIdForVersion(version);
this.tx.consensusBranchId = getDefaultConsensusBranchIdForVersion(network, version);
}
// For Zcash transactions, we do not have to have non-witness UTXO data for non-segwit
// transactions because zcash hashes the value directly. Thus, it is unnecessary to have
// the previous transaction hash on the unspent.
signInput(inputIndex: number, keyPair: Signer, sighashTypes?: number[]): this {
return withUnsafeNonSegwit(this, super.signInput.bind(this, inputIndex, keyPair, sighashTypes));
}
validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Buffer): boolean {
return withUnsafeNonSegwit(this, super.validateSignaturesOfInput.bind(this, inputIndex, validator, pubkey));
}
private setPropertyCheckSignatures(propName: keyof ZcashTransaction<bigint>, value: unknown) {
if (this.tx[propName] === value) {
return;
}
this.checkForSignatures(propName);
this.tx[propName] = value as any;
}
setConsensusBranchId(consensusBranchId: number): void {
typeforce(types.UInt32, consensusBranchId);
this.setPropertyCheckSignatures('consensusBranchId', consensusBranchId);
}
setVersionGroupId(versionGroupId: number): void {
typeforce(types.UInt32, versionGroupId);
this.setPropertyCheckSignatures('versionGroupId', versionGroupId);
}
setExpiryHeight(expiryHeight: number): void {
typeforce(types.UInt32, expiryHeight);
this.setPropertyCheckSignatures('expiryHeight', expiryHeight);
}
clone(): this {
return ZcashPsbt.fromBuffer(this.toBuffer(), { network: this.network }) as this;
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!