PHP WebShell
Текущая директория: /opt/BitGoJS/node_modules/avalanche/src/common
Просмотр файла: output.ts
/**
* @packageDocumentation
* @module Common-Output
*/
import { Buffer } from "buffer/"
import BN from "bn.js"
import BinTools from "../utils/bintools"
import { NBytes } from "./nbytes"
import { UnixNow } from "../utils/helperfunctions"
import {
Serializable,
Serialization,
SerializedEncoding
} from "../utils/serialization"
import { ChecksumError, AddressError, AddressIndexError } from "../utils/errors"
/**
* @ignore
*/
const bintools: BinTools = BinTools.getInstance()
const serialization: Serialization = Serialization.getInstance()
/**
* Class for representing an address used in [[Output]] types
*/
export class Address extends NBytes {
protected _typeName = "Address"
protected _typeID = undefined
//serialize and deserialize both are inherited
protected bytes = Buffer.alloc(20)
protected bsize = 20
/**
* Returns a function used to sort an array of [[Address]]es
*/
static comparator =
(): ((a: Address, b: Address) => 1 | -1 | 0) =>
(a: Address, b: Address): 1 | -1 | 0 =>
Buffer.compare(a.toBuffer(), b.toBuffer()) as 1 | -1 | 0
/**
* Returns a base-58 representation of the [[Address]].
*/
toString(): string {
return bintools.cb58Encode(this.toBuffer())
}
/**
* Takes a base-58 string containing an [[Address]], parses it, populates the class, and returns the length of the Address in bytes.
*
* @param bytes A base-58 string containing a raw [[Address]]
*
* @returns The length of the raw [[Address]]
*/
fromString(addr: string): number {
const addrbuff: Buffer = bintools.b58ToBuffer(addr)
if (addrbuff.length === 24 && bintools.validateChecksum(addrbuff)) {
const newbuff: Buffer = bintools.copyFrom(
addrbuff,
0,
addrbuff.length - 4
)
if (newbuff.length === 20) {
this.bytes = newbuff
}
} else if (addrbuff.length === 24) {
throw new ChecksumError(
"Error - Address.fromString: invalid checksum on address"
)
} else if (addrbuff.length === 20) {
this.bytes = addrbuff
} else {
/* istanbul ignore next */
throw new AddressError("Error - Address.fromString: invalid address")
}
return this.getSize()
}
clone(): this {
let newbase: Address = new Address()
newbase.fromBuffer(this.toBuffer())
return newbase as this
}
create(...args: any[]): this {
return new Address() as this
}
/**
* Class for representing an address used in [[Output]] types
*/
constructor() {
super()
}
}
/**
* Defines the most basic values for output ownership. Mostly inherited from, but can be used in population of NFT Owner data.
*/
export class OutputOwners extends Serializable {
protected _typeName = "OutputOwners"
protected _typeID = undefined
serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
return {
...fields,
locktime: serialization.encoder(
this.locktime,
encoding,
"Buffer",
"decimalString",
8
),
threshold: serialization.encoder(
this.threshold,
encoding,
"Buffer",
"decimalString",
4
),
addresses: this.addresses.map((a: Address): object =>
a.serialize(encoding)
)
}
}
deserialize(fields: object, encoding: SerializedEncoding = "hex") {
super.deserialize(fields, encoding)
this.locktime = serialization.decoder(
fields["locktime"],
encoding,
"decimalString",
"Buffer",
8
)
this.threshold = serialization.decoder(
fields["threshold"],
encoding,
"decimalString",
"Buffer",
4
)
this.addresses = fields["addresses"].map((a: object) => {
let addr: Address = new Address()
addr.deserialize(a, encoding)
return addr
})
this.numaddrs = Buffer.alloc(4)
this.numaddrs.writeUInt32BE(this.addresses.length, 0)
}
protected locktime: Buffer = Buffer.alloc(8)
protected threshold: Buffer = Buffer.alloc(4)
protected numaddrs: Buffer = Buffer.alloc(4)
protected addresses: Address[] = []
/**
* Returns the threshold of signers required to spend this output.
*/
getThreshold = (): number => this.threshold.readUInt32BE(0)
/**
* Returns the a {@link https://github.com/indutny/bn.js/|BN} repersenting the UNIX Timestamp when the lock is made available.
*/
getLocktime = (): BN => bintools.fromBufferToBN(this.locktime)
/**
* Returns an array of {@link https://github.com/feross/buffer|Buffer}s for the addresses.
*/
getAddresses = (): Buffer[] => {
const result: Buffer[] = []
for (let i: number = 0; i < this.addresses.length; i++) {
result.push(this.addresses[`${i}`].toBuffer())
}
return result
}
/**
* Returns the index of the address.
*
* @param address A {@link https://github.com/feross/buffer|Buffer} of the address to look up to return its index.
*
* @returns The index of the address.
*/
getAddressIdx = (address: Buffer): number => {
for (let i: number = 0; i < this.addresses.length; i++) {
if (
this.addresses[`${i}`].toBuffer().toString("hex") ===
address.toString("hex")
) {
return i
}
}
/* istanbul ignore next */
return -1
}
/**
* Returns the address from the index provided.
*
* @param idx The index of the address.
*
* @returns Returns the string representing the address.
*/
getAddress = (idx: number): Buffer => {
if (idx < this.addresses.length) {
return this.addresses[`${idx}`].toBuffer()
}
throw new AddressIndexError("Error - Output.getAddress: idx out of range")
}
/**
* Given an array of address {@link https://github.com/feross/buffer|Buffer}s and an optional timestamp, returns true if the addresses meet the threshold required to spend the output.
*/
meetsThreshold = (addresses: Buffer[], asOf: BN = undefined): boolean => {
let now: BN
if (typeof asOf === "undefined") {
now = UnixNow()
} else {
now = asOf
}
const qualified: Buffer[] = this.getSpenders(addresses, now)
const threshold: number = this.threshold.readUInt32BE(0)
if (qualified.length >= threshold) {
return true
}
return false
}
/**
* Given an array of addresses and an optional timestamp, select an array of address {@link https://github.com/feross/buffer|Buffer}s of qualified spenders for the output.
*/
getSpenders = (addresses: Buffer[], asOf: BN = undefined): Buffer[] => {
const qualified: Buffer[] = []
let now: BN
if (typeof asOf === "undefined") {
now = UnixNow()
} else {
now = asOf
}
const locktime: BN = bintools.fromBufferToBN(this.locktime)
if (now.lte(locktime)) {
// not unlocked, not spendable
return qualified
}
const threshold: number = this.threshold.readUInt32BE(0)
for (
let i: number = 0;
i < this.addresses.length && qualified.length < threshold;
i++
) {
for (
let j: number = 0;
j < addresses.length && qualified.length < threshold;
j++
) {
if (
addresses[`${j}`].toString("hex") ===
this.addresses[`${i}`].toBuffer().toString("hex")
) {
qualified.push(addresses[`${j}`])
}
}
}
return qualified
}
/**
* Returns a base-58 string representing the [[Output]].
*/
fromBuffer(bytes: Buffer, offset: number = 0): number {
this.locktime = bintools.copyFrom(bytes, offset, offset + 8)
offset += 8
this.threshold = bintools.copyFrom(bytes, offset, offset + 4)
offset += 4
this.numaddrs = bintools.copyFrom(bytes, offset, offset + 4)
offset += 4
const numaddrs: number = this.numaddrs.readUInt32BE(0)
this.addresses = []
for (let i: number = 0; i < numaddrs; i++) {
const addr: Address = new Address()
offset = addr.fromBuffer(bytes, offset)
this.addresses.push(addr)
}
this.addresses.sort(Address.comparator())
return offset
}
/**
* Returns the buffer representing the [[Output]] instance.
*/
toBuffer(): Buffer {
this.addresses.sort(Address.comparator())
this.numaddrs.writeUInt32BE(this.addresses.length, 0)
let bsize: number =
this.locktime.length + this.threshold.length + this.numaddrs.length
const barr: Buffer[] = [this.locktime, this.threshold, this.numaddrs]
for (let i: number = 0; i < this.addresses.length; i++) {
const b: Buffer = this.addresses[`${i}`].toBuffer()
barr.push(b)
bsize += b.length
}
return Buffer.concat(barr, bsize)
}
/**
* Returns a base-58 string representing the [[Output]].
*/
toString(): string {
return bintools.bufferToB58(this.toBuffer())
}
static comparator =
(): ((a: Output, b: Output) => 1 | -1 | 0) =>
(a: Output, b: Output): 1 | -1 | 0 => {
const aoutid: Buffer = Buffer.alloc(4)
aoutid.writeUInt32BE(a.getOutputID(), 0)
const abuff: Buffer = a.toBuffer()
const boutid: Buffer = Buffer.alloc(4)
boutid.writeUInt32BE(b.getOutputID(), 0)
const bbuff: Buffer = b.toBuffer()
const asort: Buffer = Buffer.concat(
[aoutid, abuff],
aoutid.length + abuff.length
)
const bsort: Buffer = Buffer.concat(
[boutid, bbuff],
boutid.length + bbuff.length
)
return Buffer.compare(asort, bsort) as 1 | -1 | 0
}
/**
* An [[Output]] class which contains addresses, locktimes, and thresholds.
*
* @param addresses An array of {@link https://github.com/feross/buffer|Buffer}s representing output owner's addresses
* @param locktime A {@link https://github.com/indutny/bn.js/|BN} representing the locktime
* @param threshold A number representing the the threshold number of signers required to sign the transaction
*/
constructor(
addresses: Buffer[] = undefined,
locktime: BN = undefined,
threshold: number = undefined
) {
super()
if (typeof addresses !== "undefined" && addresses.length) {
const addrs: Address[] = []
for (let i: number = 0; i < addresses.length; i++) {
addrs[`${i}`] = new Address()
addrs[`${i}`].fromBuffer(addresses[`${i}`])
}
this.addresses = addrs
this.addresses.sort(Address.comparator())
this.numaddrs.writeUInt32BE(this.addresses.length, 0)
}
if (typeof threshold !== undefined) {
this.threshold.writeUInt32BE(threshold || 1, 0)
}
if (typeof locktime !== "undefined") {
this.locktime = bintools.fromBNToBuffer(locktime, 8)
}
}
}
export abstract class Output extends OutputOwners {
protected _typeName = "Output"
protected _typeID = undefined
//serialize and deserialize both are inherited
/**
* Returns the outputID for the output which tells parsers what type it is
*/
abstract getOutputID(): number
abstract clone(): this
abstract create(...args: any[]): this
abstract select(id: number, ...args: any[]): Output
/**
*
* @param assetID An assetID which is wrapped around the Buffer of the Output
*
* Must be implemented to use the appropriate TransferableOutput for the VM.
*/
abstract makeTransferable(assetID: Buffer): StandardTransferableOutput
}
export abstract class StandardParseableOutput extends Serializable {
protected _typeName = "StandardParseableOutput"
protected _typeID = undefined
serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
return {
...fields,
output: this.output.serialize(encoding)
}
}
protected output: Output
/**
* Returns a function used to sort an array of [[ParseableOutput]]s
*/
static comparator =
(): ((
a: StandardParseableOutput,
b: StandardParseableOutput
) => 1 | -1 | 0) =>
(a: StandardParseableOutput, b: StandardParseableOutput): 1 | -1 | 0 => {
const sorta = a.toBuffer()
const sortb = b.toBuffer()
return Buffer.compare(sorta, sortb) as 1 | -1 | 0
}
getOutput = (): Output => this.output
// must be implemented to select output types for the VM in question
abstract fromBuffer(bytes: Buffer, offset?: number): number
toBuffer(): Buffer {
const outbuff: Buffer = this.output.toBuffer()
const outid: Buffer = Buffer.alloc(4)
outid.writeUInt32BE(this.output.getOutputID(), 0)
const barr: Buffer[] = [outid, outbuff]
return Buffer.concat(barr, outid.length + outbuff.length)
}
/**
* Class representing an [[ParseableOutput]] for a transaction.
*
* @param output A number representing the InputID of the [[ParseableOutput]]
*/
constructor(output: Output = undefined) {
super()
if (output instanceof Output) {
this.output = output
}
}
}
export abstract class StandardTransferableOutput extends StandardParseableOutput {
protected _typeName = "StandardTransferableOutput"
protected _typeID = undefined
serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
return {
...fields,
assetID: serialization.encoder(this.assetID, encoding, "Buffer", "cb58")
}
}
deserialize(fields: object, encoding: SerializedEncoding = "hex") {
super.deserialize(fields, encoding)
this.assetID = serialization.decoder(
fields["assetID"],
encoding,
"cb58",
"Buffer",
32
)
}
protected assetID: Buffer = undefined
getAssetID = (): Buffer => this.assetID
// must be implemented to select output types for the VM in question
abstract fromBuffer(bytes: Buffer, offset?: number): number
toBuffer(): Buffer {
const parseableBuff: Buffer = super.toBuffer()
const barr: Buffer[] = [this.assetID, parseableBuff]
return Buffer.concat(barr, this.assetID.length + parseableBuff.length)
}
/**
* Class representing an [[StandardTransferableOutput]] for a transaction.
*
* @param assetID A {@link https://github.com/feross/buffer|Buffer} representing the assetID of the [[Output]]
* @param output A number representing the InputID of the [[StandardTransferableOutput]]
*/
constructor(assetID: Buffer = undefined, output: Output = undefined) {
super(output)
if (typeof assetID !== "undefined") {
this.assetID = assetID
}
}
}
/**
* An [[Output]] class which specifies a token amount .
*/
export abstract class StandardAmountOutput extends Output {
protected _typeName = "StandardAmountOutput"
protected _typeID = undefined
serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
return {
...fields,
amount: serialization.encoder(
this.amount,
encoding,
"Buffer",
"decimalString",
8
)
}
}
deserialize(fields: object, encoding: SerializedEncoding = "hex") {
super.deserialize(fields, encoding)
this.amount = serialization.decoder(
fields["amount"],
encoding,
"decimalString",
"Buffer",
8
)
this.amountValue = bintools.fromBufferToBN(this.amount)
}
protected amount: Buffer = Buffer.alloc(8)
protected amountValue: BN = new BN(0)
/**
* Returns the amount as a {@link https://github.com/indutny/bn.js/|BN}.
*/
getAmount(): BN {
return this.amountValue.clone()
}
/**
* Popuates the instance from a {@link https://github.com/feross/buffer|Buffer} representing the [[StandardAmountOutput]] and returns the size of the output.
*/
fromBuffer(outbuff: Buffer, offset: number = 0): number {
this.amount = bintools.copyFrom(outbuff, offset, offset + 8)
this.amountValue = bintools.fromBufferToBN(this.amount)
offset += 8
return super.fromBuffer(outbuff, offset)
}
/**
* Returns the buffer representing the [[StandardAmountOutput]] instance.
*/
toBuffer(): Buffer {
const superbuff: Buffer = super.toBuffer()
const bsize: number = this.amount.length + superbuff.length
this.numaddrs.writeUInt32BE(this.addresses.length, 0)
const barr: Buffer[] = [this.amount, superbuff]
return Buffer.concat(barr, bsize)
}
/**
* A [[StandardAmountOutput]] class which issues a payment on an assetID.
*
* @param amount A {@link https://github.com/indutny/bn.js/|BN} representing the amount in the output
* @param addresses An array of {@link https://github.com/feross/buffer|Buffer}s representing addresses
* @param locktime A {@link https://github.com/indutny/bn.js/|BN} representing the locktime
* @param threshold A number representing the the threshold number of signers required to sign the transaction
*/
constructor(
amount: BN = undefined,
addresses: Buffer[] = undefined,
locktime: BN = undefined,
threshold: number = undefined
) {
super(addresses, locktime, threshold)
if (typeof amount !== "undefined") {
this.amountValue = amount.clone()
this.amount = bintools.fromBNToBuffer(amount, 8)
}
}
}
/**
* An [[Output]] class which specifies an NFT.
*/
export abstract class BaseNFTOutput extends Output {
protected _typeName = "BaseNFTOutput"
protected _typeID = undefined
serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
return {
...fields,
groupID: serialization.encoder(
this.groupID,
encoding,
"Buffer",
"decimalString",
4
)
}
}
deserialize(fields: object, encoding: SerializedEncoding = "hex") {
super.deserialize(fields, encoding)
this.groupID = serialization.decoder(
fields["groupID"],
encoding,
"decimalString",
"Buffer",
4
)
}
protected groupID: Buffer = Buffer.alloc(4)
/**
* Returns the groupID as a number.
*/
getGroupID = (): number => {
return this.groupID.readUInt32BE(0)
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!