PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/avalanche/src/common
Просмотр файла: utxos.ts
/**
* @packageDocumentation
* @module Common-UTXOs
*/
import { Buffer } from "buffer/"
import BinTools from "../utils/bintools"
import BN from "bn.js"
import { Output, StandardAmountOutput } from "./output"
import { UnixNow } from "../utils/helperfunctions"
import { MergeRule } from "../utils/constants"
import {
Serializable,
Serialization,
SerializedEncoding
} from "../utils/serialization"
import { MergeRuleError } from "../utils/errors"
/**
* @ignore
*/
const bintools: BinTools = BinTools.getInstance()
const serialization: Serialization = Serialization.getInstance()
/**
* Class for representing a single StandardUTXO.
*/
export abstract class StandardUTXO extends Serializable {
protected _typeName = "StandardUTXO"
protected _typeID = undefined
serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
return {
...fields,
codecID: serialization.encoder(
this.codecID,
encoding,
"Buffer",
"decimalString"
),
txid: serialization.encoder(this.txid, encoding, "Buffer", "cb58"),
outputidx: serialization.encoder(
this.outputidx,
encoding,
"Buffer",
"decimalString"
),
assetID: serialization.encoder(this.assetID, encoding, "Buffer", "cb58"),
output: this.output.serialize(encoding)
}
}
deserialize(fields: object, encoding: SerializedEncoding = "hex") {
super.deserialize(fields, encoding)
this.codecID = serialization.decoder(
fields["codecID"],
encoding,
"decimalString",
"Buffer",
2
)
this.txid = serialization.decoder(
fields["txid"],
encoding,
"cb58",
"Buffer",
32
)
this.outputidx = serialization.decoder(
fields["outputidx"],
encoding,
"decimalString",
"Buffer",
4
)
this.assetID = serialization.decoder(
fields["assetID"],
encoding,
"cb58",
"Buffer",
32
)
}
protected codecID: Buffer = Buffer.alloc(2)
protected txid: Buffer = Buffer.alloc(32)
protected outputidx: Buffer = Buffer.alloc(4)
protected assetID: Buffer = Buffer.alloc(32)
protected output: Output = undefined
/**
* Returns the numeric representation of the CodecID.
*/
getCodecID = (): /* istanbul ignore next */ number =>
this.codecID.readUInt8(0)
/**
* Returns the {@link https://github.com/feross/buffer|Buffer} representation of the CodecID
*/
getCodecIDBuffer = (): Buffer => this.codecID
/**
* Returns a {@link https://github.com/feross/buffer|Buffer} of the TxID.
*/
getTxID = (): /* istanbul ignore next */ Buffer => this.txid
/**
* Returns a {@link https://github.com/feross/buffer|Buffer} of the OutputIdx.
*/
getOutputIdx = (): /* istanbul ignore next */ Buffer => this.outputidx
/**
* Returns the assetID as a {@link https://github.com/feross/buffer|Buffer}.
*/
getAssetID = (): Buffer => this.assetID
/**
* Returns the UTXOID as a base-58 string (UTXOID is a string )
*/
getUTXOID = (): /* istanbul ignore next */ string =>
bintools.bufferToB58(Buffer.concat([this.getTxID(), this.getOutputIdx()]))
/**
* Returns a reference to the output
*/
getOutput = (): Output => this.output
/**
* Takes a {@link https://github.com/feross/buffer|Buffer} containing an [[StandardUTXO]], parses it, populates the class, and returns the length of the StandardUTXO in bytes.
*
* @param bytes A {@link https://github.com/feross/buffer|Buffer} containing a raw [[StandardUTXO]]
*/
abstract fromBuffer(bytes: Buffer, offset?: number): number
/**
* Returns a {@link https://github.com/feross/buffer|Buffer} representation of the [[StandardUTXO]].
*/
toBuffer(): Buffer {
const outbuff: Buffer = this.output.toBuffer()
const outputidbuffer: Buffer = Buffer.alloc(4)
outputidbuffer.writeUInt32BE(this.output.getOutputID(), 0)
const barr: Buffer[] = [
this.codecID,
this.txid,
this.outputidx,
this.assetID,
outputidbuffer,
outbuff
]
return Buffer.concat(
barr,
this.codecID.length +
this.txid.length +
this.outputidx.length +
this.assetID.length +
outputidbuffer.length +
outbuff.length
)
}
abstract fromString(serialized: string): number
abstract toString(): string
abstract clone(): this
abstract create(
codecID?: number,
txid?: Buffer,
outputidx?: Buffer | number,
assetID?: Buffer,
output?: Output
): this
/**
* Class for representing a single StandardUTXO.
*
* @param codecID Optional number which specifies the codeID of the UTXO. Default 0
* @param txID Optional {@link https://github.com/feross/buffer|Buffer} of transaction ID for the StandardUTXO
* @param txidx Optional {@link https://github.com/feross/buffer|Buffer} or number for the index of the transaction's [[Output]]
* @param assetID Optional {@link https://github.com/feross/buffer|Buffer} of the asset ID for the StandardUTXO
* @param outputid Optional {@link https://github.com/feross/buffer|Buffer} or number of the output ID for the StandardUTXO
*/
constructor(
codecID: number = 0,
txID: Buffer = undefined,
outputidx: Buffer | number = undefined,
assetID: Buffer = undefined,
output: Output = undefined
) {
super()
if (typeof codecID !== "undefined") {
this.codecID.writeUInt8(codecID, 0)
}
if (typeof txID !== "undefined") {
this.txid = txID
}
if (typeof outputidx === "number") {
this.outputidx.writeUInt32BE(outputidx, 0)
} else if (outputidx instanceof Buffer) {
this.outputidx = outputidx
}
if (typeof assetID !== "undefined") {
this.assetID = assetID
}
if (typeof output !== "undefined") {
this.output = output
}
}
}
/**
* Class representing a set of [[StandardUTXO]]s.
*/
export abstract class StandardUTXOSet<
UTXOClass extends StandardUTXO
> extends Serializable {
protected _typeName = "StandardUTXOSet"
protected _typeID = undefined
serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
let utxos = {}
for (let utxoid in this.utxos) {
let utxoidCleaned: string = serialization.encoder(
utxoid,
encoding,
"base58",
"base58"
)
utxos[`${utxoidCleaned}`] = this.utxos[`${utxoid}`].serialize(encoding)
}
let addressUTXOs = {}
for (let address in this.addressUTXOs) {
let addressCleaned: string = serialization.encoder(
address,
encoding,
"hex",
"cb58"
)
let utxobalance = {}
for (let utxoid in this.addressUTXOs[`${address}`]) {
let utxoidCleaned: string = serialization.encoder(
utxoid,
encoding,
"base58",
"base58"
)
utxobalance[`${utxoidCleaned}`] = serialization.encoder(
this.addressUTXOs[`${address}`][`${utxoid}`],
encoding,
"BN",
"decimalString"
)
}
addressUTXOs[`${addressCleaned}`] = utxobalance
}
return {
...fields,
utxos,
addressUTXOs
}
}
protected utxos: { [utxoid: string]: UTXOClass } = {}
protected addressUTXOs: { [address: string]: { [utxoid: string]: BN } } = {} // maps address to utxoids:locktime
abstract parseUTXO(utxo: UTXOClass | string): UTXOClass
/**
* Returns true if the [[StandardUTXO]] is in the StandardUTXOSet.
*
* @param utxo Either a [[StandardUTXO]] a cb58 serialized string representing a StandardUTXO
*/
includes = (utxo: UTXOClass | string): boolean => {
let utxoX: UTXOClass = undefined
let utxoid: string = undefined
try {
utxoX = this.parseUTXO(utxo)
utxoid = utxoX.getUTXOID()
} catch (e) {
if (e instanceof Error) {
console.log(e.message)
} else {
console.log(e)
}
return false
}
return utxoid in this.utxos
}
/**
* Adds a [[StandardUTXO]] to the StandardUTXOSet.
*
* @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO
* @param overwrite If true, if the UTXOID already exists, overwrite it... default false
*
* @returns A [[StandardUTXO]] if one was added and undefined if nothing was added.
*/
add(utxo: UTXOClass | string, overwrite: boolean = false): UTXOClass {
let utxovar: UTXOClass = undefined
try {
utxovar = this.parseUTXO(utxo)
} catch (e) {
if (e instanceof Error) {
console.log(e.message)
} else {
console.log(e)
}
return undefined
}
const utxoid: string = utxovar.getUTXOID()
if (!(utxoid in this.utxos) || overwrite === true) {
this.utxos[`${utxoid}`] = utxovar
const addresses: Buffer[] = utxovar.getOutput().getAddresses()
const locktime: BN = utxovar.getOutput().getLocktime()
for (let i: number = 0; i < addresses.length; i++) {
const address: string = addresses[`${i}`].toString("hex")
if (!(address in this.addressUTXOs)) {
this.addressUTXOs[`${address}`] = {}
}
this.addressUTXOs[`${address}`][`${utxoid}`] = locktime
}
return utxovar
}
return undefined
}
/**
* Adds an array of [[StandardUTXO]]s to the [[StandardUTXOSet]].
*
* @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO
* @param overwrite If true, if the UTXOID already exists, overwrite it... default false
*
* @returns An array of StandardUTXOs which were added.
*/
addArray(
utxos: string[] | UTXOClass[],
overwrite: boolean = false
): StandardUTXO[] {
const added: UTXOClass[] = []
for (let i: number = 0; i < utxos.length; i++) {
let result: UTXOClass = this.add(utxos[`${i}`], overwrite)
if (typeof result !== "undefined") {
added.push(result)
}
}
return added
}
/**
* Removes a [[StandardUTXO]] from the [[StandardUTXOSet]] if it exists.
*
* @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO
*
* @returns A [[StandardUTXO]] if it was removed and undefined if nothing was removed.
*/
remove = (utxo: UTXOClass | string): UTXOClass => {
let utxovar: UTXOClass = undefined
try {
utxovar = this.parseUTXO(utxo)
} catch (e) {
if (e instanceof Error) {
console.log(e.message)
} else {
console.log(e)
}
return undefined
}
const utxoid: string = utxovar.getUTXOID()
if (!(utxoid in this.utxos)) {
return undefined
}
delete this.utxos[`${utxoid}`]
const addresses = Object.keys(this.addressUTXOs)
for (let i: number = 0; i < addresses.length; i++) {
if (utxoid in this.addressUTXOs[addresses[`${i}`]]) {
delete this.addressUTXOs[addresses[`${i}`]][`${utxoid}`]
}
}
return utxovar
}
/**
* Removes an array of [[StandardUTXO]]s to the [[StandardUTXOSet]].
*
* @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO
* @param overwrite If true, if the UTXOID already exists, overwrite it... default false
*
* @returns An array of UTXOs which were removed.
*/
removeArray = (utxos: string[] | UTXOClass[]): UTXOClass[] => {
const removed: UTXOClass[] = []
for (let i: number = 0; i < utxos.length; i++) {
const result: UTXOClass = this.remove(utxos[`${i}`])
if (typeof result !== "undefined") {
removed.push(result)
}
}
return removed
}
/**
* Gets a [[StandardUTXO]] from the [[StandardUTXOSet]] by its UTXOID.
*
* @param utxoid String representing the UTXOID
*
* @returns A [[StandardUTXO]] if it exists in the set.
*/
getUTXO = (utxoid: string): UTXOClass => this.utxos[`${utxoid}`]
/**
* Gets all the [[StandardUTXO]]s, optionally that match with UTXOIDs in an array
*
* @param utxoids An optional array of UTXOIDs, returns all [[StandardUTXO]]s if not provided
*
* @returns An array of [[StandardUTXO]]s.
*/
getAllUTXOs = (utxoids: string[] = undefined): UTXOClass[] => {
let results: UTXOClass[] = []
if (typeof utxoids !== "undefined" && Array.isArray(utxoids)) {
results = utxoids
.filter((utxoid) => this.utxos[`${utxoid}`])
.map((utxoid) => this.utxos[`${utxoid}`])
} else {
results = Object.values(this.utxos)
}
return results
}
/**
* Gets all the [[StandardUTXO]]s as strings, optionally that match with UTXOIDs in an array.
*
* @param utxoids An optional array of UTXOIDs, returns all [[StandardUTXO]]s if not provided
*
* @returns An array of [[StandardUTXO]]s as cb58 serialized strings.
*/
getAllUTXOStrings = (utxoids: string[] = undefined): string[] => {
const results: string[] = []
const utxos = Object.keys(this.utxos)
if (typeof utxoids !== "undefined" && Array.isArray(utxoids)) {
for (let i: number = 0; i < utxoids.length; i++) {
if (utxoids[`${i}`] in this.utxos) {
results.push(this.utxos[utxoids[`${i}`]].toString())
}
}
} else {
for (const u of utxos) {
results.push(this.utxos[`${u}`].toString())
}
}
return results
}
/**
* Given an address or array of addresses, returns all the UTXOIDs for those addresses
*
* @param address An array of address {@link https://github.com/feross/buffer|Buffer}s
* @param spendable If true, only retrieves UTXOIDs whose locktime has passed
*
* @returns An array of addresses.
*/
getUTXOIDs = (
addresses: Buffer[] = undefined,
spendable: boolean = true
): string[] => {
if (typeof addresses !== "undefined") {
const results: string[] = []
const now: BN = UnixNow()
for (let i: number = 0; i < addresses.length; i++) {
if (addresses[`${i}`].toString("hex") in this.addressUTXOs) {
const entries = Object.entries(
this.addressUTXOs[addresses[`${i}`].toString("hex")]
)
for (const [utxoid, locktime] of entries) {
if (
(results.indexOf(utxoid) === -1 &&
spendable &&
locktime.lte(now)) ||
!spendable
) {
results.push(utxoid)
}
}
}
}
return results
}
return Object.keys(this.utxos)
}
/**
* Gets the addresses in the [[StandardUTXOSet]] and returns an array of {@link https://github.com/feross/buffer|Buffer}.
*/
getAddresses = (): Buffer[] =>
Object.keys(this.addressUTXOs).map((k) => Buffer.from(k, "hex"))
/**
* Returns the balance of a set of addresses in the StandardUTXOSet.
*
* @param addresses An array of addresses
* @param assetID Either a {@link https://github.com/feross/buffer|Buffer} or an cb58 serialized representation of an AssetID
* @param asOf The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN}
*
* @returns Returns the total balance as a {@link https://github.com/indutny/bn.js/|BN}.
*/
getBalance = (
addresses: Buffer[],
assetID: Buffer | string,
asOf: BN = undefined
): BN => {
const utxoids: string[] = this.getUTXOIDs(addresses)
const utxos: StandardUTXO[] = this.getAllUTXOs(utxoids)
let spend: BN = new BN(0)
let asset: Buffer
if (typeof assetID === "string") {
asset = bintools.cb58Decode(assetID)
} else {
asset = assetID
}
for (let i: number = 0; i < utxos.length; i++) {
if (
utxos[`${i}`].getOutput() instanceof StandardAmountOutput &&
utxos[`${i}`].getAssetID().toString("hex") === asset.toString("hex") &&
utxos[`${i}`].getOutput().meetsThreshold(addresses, asOf)
) {
spend = spend.add(
(utxos[`${i}`].getOutput() as StandardAmountOutput).getAmount()
)
}
}
return spend
}
/**
* Gets all the Asset IDs, optionally that match with Asset IDs in an array
*
* @param utxoids An optional array of Addresses as string or Buffer, returns all Asset IDs if not provided
*
* @returns An array of {@link https://github.com/feross/buffer|Buffer} representing the Asset IDs.
*/
getAssetIDs = (addresses: Buffer[] = undefined): Buffer[] => {
const results: Set<Buffer> = new Set()
let utxoids: string[] = []
if (typeof addresses !== "undefined") {
utxoids = this.getUTXOIDs(addresses)
} else {
utxoids = this.getUTXOIDs()
}
for (let i: number = 0; i < utxoids.length; i++) {
if (utxoids[`${i}`] in this.utxos && !(utxoids[`${i}`] in results)) {
results.add(this.utxos[utxoids[`${i}`]].getAssetID())
}
}
return [...results]
}
abstract clone(): this
abstract create(...args: any[]): this
filter(
args: any[],
lambda: (utxo: UTXOClass, ...largs: any[]) => boolean
): this {
let newset: this = this.clone()
let utxos: UTXOClass[] = this.getAllUTXOs()
for (let i: number = 0; i < utxos.length; i++) {
if (lambda(utxos[`${i}`], ...args) === false) {
newset.remove(utxos[`${i}`])
}
}
return newset
}
/**
* Returns a new set with copy of UTXOs in this and set parameter.
*
* @param utxoset The [[StandardUTXOSet]] to merge with this one
* @param hasUTXOIDs Will subselect a set of [[StandardUTXO]]s which have the UTXOIDs provided in this array, defults to all UTXOs
*
* @returns A new StandardUTXOSet that contains all the filtered elements.
*/
merge = (utxoset: this, hasUTXOIDs: string[] = undefined): this => {
const results: this = this.create()
const utxos1: UTXOClass[] = this.getAllUTXOs(hasUTXOIDs)
const utxos2: UTXOClass[] = utxoset.getAllUTXOs(hasUTXOIDs)
const process = (utxo: UTXOClass) => {
results.add(utxo)
}
utxos1.forEach(process)
utxos2.forEach(process)
return results as this
}
/**
* Set intersetion between this set and a parameter.
*
* @param utxoset The set to intersect
*
* @returns A new StandardUTXOSet containing the intersection
*/
intersection = (utxoset: this): this => {
const us1: string[] = this.getUTXOIDs()
const us2: string[] = utxoset.getUTXOIDs()
const results: string[] = us1.filter((utxoid) => us2.includes(utxoid))
return this.merge(utxoset, results) as this
}
/**
* Set difference between this set and a parameter.
*
* @param utxoset The set to difference
*
* @returns A new StandardUTXOSet containing the difference
*/
difference = (utxoset: this): this => {
const us1: string[] = this.getUTXOIDs()
const us2: string[] = utxoset.getUTXOIDs()
const results: string[] = us1.filter((utxoid) => !us2.includes(utxoid))
return this.merge(utxoset, results) as this
}
/**
* Set symmetrical difference between this set and a parameter.
*
* @param utxoset The set to symmetrical difference
*
* @returns A new StandardUTXOSet containing the symmetrical difference
*/
symDifference = (utxoset: this): this => {
const us1: string[] = this.getUTXOIDs()
const us2: string[] = utxoset.getUTXOIDs()
const results: string[] = us1
.filter((utxoid) => !us2.includes(utxoid))
.concat(us2.filter((utxoid) => !us1.includes(utxoid)))
return this.merge(utxoset, results) as this
}
/**
* Set union between this set and a parameter.
*
* @param utxoset The set to union
*
* @returns A new StandardUTXOSet containing the union
*/
union = (utxoset: this): this => this.merge(utxoset) as this
/**
* Merges a set by the rule provided.
*
* @param utxoset The set to merge by the MergeRule
* @param mergeRule The [[MergeRule]] to apply
*
* @returns A new StandardUTXOSet containing the merged data
*
* @remarks
* The merge rules are as follows:
* * "intersection" - the intersection of the set
* * "differenceSelf" - the difference between the existing data and new set
* * "differenceNew" - the difference between the new data and the existing set
* * "symDifference" - the union of the differences between both sets of data
* * "union" - the unique set of all elements contained in both sets
* * "unionMinusNew" - the unique set of all elements contained in both sets, excluding values only found in the new set
* * "unionMinusSelf" - the unique set of all elements contained in both sets, excluding values only found in the existing set
*/
mergeByRule = (utxoset: this, mergeRule: MergeRule): this => {
let uSet: this
switch (mergeRule) {
case "intersection":
return this.intersection(utxoset)
case "differenceSelf":
return this.difference(utxoset)
case "differenceNew":
return utxoset.difference(this) as this
case "symDifference":
return this.symDifference(utxoset)
case "union":
return this.union(utxoset)
case "unionMinusNew":
uSet = this.union(utxoset)
return uSet.difference(utxoset) as this
case "unionMinusSelf":
uSet = this.union(utxoset)
return uSet.difference(this) as this
default:
throw new MergeRuleError(
"Error - StandardUTXOSet.mergeByRule: bad MergeRule"
)
}
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!