PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-core/src
Просмотр файла: dustThreshold.ts
import * as utxolib from '@bitgo/utxo-lib';
/**
* Checks if the output script is a witness script or not
* @param script
* @returns true if the script is a witness script
*/
function isWitnessOutputScript(script: Buffer): boolean {
/**
* Source: https://github.com/bitcoin/bitcoin/blob/v28.1/src/script/script.cpp#L241-L257
* A witness program is any valid CScript that consists of a 1-byte push opcode
* followed by a data push between 2 and 40 bytes.
*/
if (script.length < 4 || script.length > 42) {
return false;
}
if (script[0] !== utxolib.opcodes.OP_0 && (script[0] < utxolib.opcodes.OP_1 || script[0] > utxolib.opcodes.OP_16)) {
return false;
}
return script[1] + 2 === script.length;
}
/*
The dust threshold for most UTXO coins is dependent on multiple factors:
(1) spendability of the output (OP_RETURNs are allowed to be 0 sized)
(2) whether it is a witness or non-witness output
(3) a particular fee rate (GetDiscardRate())
I will do the analysis mostly for bitcoin here and then generalize.
On the indexer we use `sendrawtransaction`, which calls `IsStandardTx` like this
https://github.com/bitcoin/bitcoin/blob/v28.0/src/kernel/mempool_options.h#L47
```
if (
m_pool.m_opts.require_standard &&
!IsStandardTx(tx,
m_pool.m_opts.max_datacarrier_bytes,
m_pool.m_opts.permit_bare_multisig,
m_pool.m_opts.dust_relay_feerate, reason))
```
The `dust_relay_feerate` in this context is a hardcoded constant:
https://github.com/bitcoin/bitcoin/blob/v28.0/src/policy/policy.h#L50-L55
(that can actually be overridden with a hidden command
line parameter: https://bitcoin.stackexchange.com/a/41082/137601)
There we call `IsDust`
https://github.com/bitcoin/bitcoin/blob/v28.0/src/policy/policy.cpp#L144-L146
```
if (IsDust(txout, dust_relay_fee)) {
reason = "dust";
return false;
}
```
Which calls `GetDustThreshold`,
https://github.com/bitcoin/bitcoin/blob/v28.0/src/policy/policy.cpp#L67
The implementation of `GetDustThreshold` computes the minimal transaction size that can spend the output, and computes
a minimum fee for that transaction size based on the `dust_relay_fee` (FeeRate) parameter.
The different utxo implementations differ in these ways:
- some have a fixed, satoshi amount dust limit (doge, zec)
- some have a different dust_relay_fee
*/
type DustLimit = { feeRateSatKB: number } | { satAmount: number };
function getDustRelayLimit(network: utxolib.Network): DustLimit {
network = utxolib.getMainnet(network);
switch (network) {
case utxolib.networks.bitcoin:
case utxolib.networks.bitcoingold:
case utxolib.networks.dash:
// btc: https://github.com/bitcoin/bitcoin/blob/v28.0/src/policy/policy.h#L50-L55
// btg: https://github.com/BTCGPU/BTCGPU/blob/v0.17.3/src/policy/policy.h#L48
// dash: https://github.com/dashpay/dash/blob/v22.0.0-beta.1/src/policy/policy.h#L41-L46
return { feeRateSatKB: 3000 };
case utxolib.networks.bitcoincash:
// https://github.com/bitcoin-cash-node/bitcoin-cash-node/blob/v27.1.0/src/policy/policy.h#L76-L83
// I actually haven't looked at BSV and am depressed that I still need to handle the case here
return { feeRateSatKB: 1000 };
case utxolib.networks.dogecoin:
// https://github.com/dogecoin/dogecoin/blob/v1.14.8/src/policy/policy.h#L65-L81
// (COIN / 100) / 10;
return { satAmount: 1_000_000 };
case utxolib.networks.litecoin:
// https://github.com/litecoin-project/litecoin/blob/master/src/policy/policy.h#L47-L52
return { feeRateSatKB: 30_000 };
case utxolib.networks.zcash:
// https://github.com/zcash/zcash/blob/master/src/primitives/transaction.h#L396-L399
// https://github.com/zcash/zcash/blob/v6.0.0/src/policy/policy.h#L43-L89 (I don't quite get it)
return { satAmount: 300 };
case utxolib.networks.bitcoinsv:
throw new Error('deprecated coin');
default:
throw new Error('unsupported network');
}
}
function getSpendSize(network: utxolib.Network, outputSize: number, isWitness: boolean): number {
network = utxolib.getMainnet(network);
switch (network) {
case utxolib.networks.bitcoin:
case utxolib.networks.bitcoincash:
case utxolib.networks.bitcoingold:
case utxolib.networks.litecoin:
/*
btc: https://github.com/bitcoin/bitcoin/blob/v28.0/src/policy/policy.cpp#L26-L68
bch: https://github.com/bitcoin-cash-node/bitcoin-cash-node/blob/v27.1.0/src/policy/policy.cpp#L18-L36 (btc-ish)
btg: https://github.com/BTCGPU/BTCGPU/blob/v0.17.3/src/policy/policy.cpp#L18-L50 (btc-ish)
ltc: https://github.com/litecoin-project/litecoin/blob/v0.21.4/src/policy/policy.cpp#L15-L47 (btc-ish)
The fixed component here is 69.75 for isWitness=true and 150 for isWitness=false.
*/
return outputSize + 32 + 4 + 1 + 107 / (isWitness ? 4 : 1) + 4;
case utxolib.networks.dash:
// dash: https://github.com/dashpay/dash/blob/v21.1.1/src/policy/policy.cpp#L14-L30 (btc-ish)
// how did they end up with 148? I don't know
return outputSize + 148;
case utxolib.networks.dogecoin:
case utxolib.networks.zcash:
// doge: https://github.com/dogecoin/dogecoin/blob/v1.14.8/src/policy/policy.h#L65-L81 (hardcoded)
// zec: https://github.com/zcash/zcash/blob/v6.0.0/src/policy/policy.h#L43-L89 (some weird other thing, doge-ish)
throw new Error('dust limit is size-independent');
case utxolib.networks.bitcoinsv:
throw new Error('deprecated coin');
default:
throw new Error('unsupported network');
}
}
export function getDustThresholdSat(network: utxolib.Network, outputSize: number, isWitness: boolean): number {
const dustLimit = getDustRelayLimit(network);
if ('satAmount' in dustLimit) {
return dustLimit.satAmount;
}
if ('feeRateSatKB' in dustLimit) {
const spendSize = getSpendSize(network, outputSize, isWitness);
return Math.ceil((dustLimit.feeRateSatKB * spendSize) / 1000);
}
throw new Error('unexpected dustLimit');
}
export function getDustThresholdSatForOutputScript(network: utxolib.Network, script: Buffer): number {
return getDustThresholdSat(network, script.length, isWitnessOutputScript(script));
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!