PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-lib/src/bitgo/zcash
Просмотр файла: ZcashBufferutils.ts
/**
* Transaction (de)serialization helpers.
* Only supports full transparent transactions without shielded inputs or outputs.
*
* References:
* - https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L771
*/
import { TxInput, TxOutput } from 'bitcoinjs-lib';
import { BufferReader, BufferWriter } from 'bitcoinjs-lib/src/bufferutils';
import { UnsupportedTransactionError, ZcashTransaction } from './ZcashTransaction';
export const VALUE_INT64_ZERO = Buffer.from('0000000000000000', 'hex');
export function readInputs(bufferReader: BufferReader): TxInput[] {
const vinLen = bufferReader.readVarInt();
const ins: TxInput[] = [];
for (let i = 0; i < vinLen; ++i) {
ins.push({
hash: bufferReader.readSlice(32),
index: bufferReader.readUInt32(),
script: bufferReader.readVarSlice(),
sequence: bufferReader.readUInt32(),
witness: [],
});
}
return ins;
}
export function readOutputs<TNumber extends number | bigint>(
bufferReader: BufferReader,
amountType: 'number' | 'bigint' = 'number'
): TxOutput<TNumber>[] {
const voutLen = bufferReader.readVarInt();
const outs: TxOutput<TNumber>[] = [];
for (let i = 0; i < voutLen; ++i) {
outs.push({
value: (amountType === 'bigint' ? bufferReader.readUInt64BigInt() : bufferReader.readUInt64()) as TNumber,
script: bufferReader.readVarSlice(),
});
}
return outs;
}
export function readEmptyVector(bufferReader: BufferReader): void {
const n = bufferReader.readVarInt();
if (n !== 0) {
throw new UnsupportedTransactionError(`expected empty vector`);
}
}
export function readEmptyOrchardBundle(bufferReader: BufferReader): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/orchard.h#L66
// https://github.com/zcash/librustzcash/blob/edcde252de221d4851f1e5145306c2caf95453bc/zcash_primitives/src/transaction/components/orchard.rs#L36
const v = bufferReader.readUInt8();
if (v !== 0x00) {
throw new UnsupportedTransactionError(`expected byte 0x00`);
}
}
export function writeEmptyOrchardBundle(bufferWriter: BufferWriter): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/orchard.h#L66
// https://github.com/zcash/librustzcash/blob/edcde252de221d4851f1e5145306c2caf95453bc/zcash_primitives/src/transaction/components/orchard.rs#L201
bufferWriter.writeUInt8(0);
}
export function readEmptySaplingBundle(bufferReader: BufferReader): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L283
readEmptyVector(bufferReader) /* vSpendsSapling */;
readEmptyVector(bufferReader) /* vOutputsSapling */;
}
export function writeEmptySamplingBundle(bufferWriter: BufferWriter): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L283
bufferWriter.writeVarInt(0) /* vSpendsSapling */;
bufferWriter.writeVarInt(0) /* vOutputsSapling */;
}
export function fromBufferV4<TNumber extends number | bigint>(
bufferReader: BufferReader,
tx: ZcashTransaction<TNumber>,
amountType: 'number' | 'bigint' = 'number'
): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L855-L857
tx.ins = readInputs(bufferReader);
tx.outs = readOutputs<TNumber>(bufferReader, amountType);
tx.locktime = bufferReader.readUInt32();
if (tx.isOverwinterCompatible()) {
tx.expiryHeight = bufferReader.readUInt32();
}
if (tx.isSaplingCompatible()) {
const valueBalance = bufferReader.readSlice(8);
if (!valueBalance.equals(VALUE_INT64_ZERO)) {
/* istanbul ignore next */
throw new UnsupportedTransactionError(`valueBalance must be zero`);
}
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L863
readEmptySaplingBundle(bufferReader);
}
if (tx.supportsJoinSplits()) {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L869
readEmptyVector(bufferReader) /* vJoinSplit */;
}
}
export function fromBufferV5<TNumber extends number | bigint>(
bufferReader: BufferReader,
tx: ZcashTransaction<TNumber>,
amountType: 'number' | 'bigint' = 'number'
): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L815
tx.consensusBranchId = bufferReader.readUInt32();
tx.locktime = bufferReader.readUInt32();
tx.expiryHeight = bufferReader.readUInt32();
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L828
tx.ins = readInputs(bufferReader);
tx.outs = readOutputs<TNumber>(bufferReader, amountType);
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L835
readEmptySaplingBundle(bufferReader);
readEmptyOrchardBundle(bufferReader);
}
export function writeInputs(bufferWriter: BufferWriter, ins: TxInput[]): void {
bufferWriter.writeVarInt(ins.length);
ins.forEach(function (txIn) {
bufferWriter.writeSlice(txIn.hash);
bufferWriter.writeUInt32(txIn.index);
bufferWriter.writeVarSlice(txIn.script);
bufferWriter.writeUInt32(txIn.sequence);
});
}
export function writeOutputs<TNumber extends number | bigint>(
bufferWriter: BufferWriter,
outs: TxOutput<TNumber>[]
): void {
bufferWriter.writeVarInt(outs.length);
outs.forEach(function (txOut) {
if ((txOut as any).valueBuffer) {
bufferWriter.writeSlice((txOut as any).valueBuffer);
} else {
bufferWriter.writeUInt64(txOut.value);
}
bufferWriter.writeVarSlice(txOut.script);
});
}
export function toBufferV4<TNumber extends number | bigint>(
bufferWriter: BufferWriter,
tx: ZcashTransaction<TNumber>
): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L1083
writeInputs(bufferWriter, tx.ins);
writeOutputs<TNumber>(bufferWriter, tx.outs);
bufferWriter.writeUInt32(tx.locktime);
if (tx.isOverwinterCompatible()) {
bufferWriter.writeUInt32(tx.expiryHeight);
}
if (tx.isSaplingCompatible()) {
bufferWriter.writeSlice(VALUE_INT64_ZERO);
bufferWriter.writeVarInt(0); // vShieldedSpendLength
bufferWriter.writeVarInt(0); // vShieldedOutputLength
}
if (tx.supportsJoinSplits()) {
bufferWriter.writeVarInt(0); // joinsSplits length
}
}
export function toBufferV5<TNumber extends number | bigint>(
bufferWriter: BufferWriter,
tx: ZcashTransaction<TNumber>
): void {
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L825-L826
bufferWriter.writeUInt32(tx.consensusBranchId);
bufferWriter.writeUInt32(tx.locktime);
bufferWriter.writeUInt32(tx.expiryHeight);
writeInputs(bufferWriter, tx.ins);
writeOutputs<TNumber>(bufferWriter, tx.outs);
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L1063
writeEmptySamplingBundle(bufferWriter);
// https://github.com/zcash/zcash/blob/v4.5.1/src/primitives/transaction.h#L1081
writeEmptyOrchardBundle(bufferWriter);
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!