bitcoinjs-lib icon indicating copy to clipboard operation
bitcoinjs-lib copied to clipboard

Clearification on virtualSize, byteLength

Open takahser opened this issue 6 years ago • 2 comments
trafficstars

I'd like to calculate/derive, how many byte a specific Transaction weighs after being mined. There are 3 members on Transaction that deal with sizes:

  • virtualSize
  • weight
  • byteLength

I found information regarding virtualSize/vbyte and weight in the wiki entry about weight units.

Apparently vbyte = 4 * weight, while weight = maxBlockSize / 4e6.

Therefore:

  • for BTC: 1 weight = 1e6 / 4e6 = 1/4 byte => virtualSize = 4 * weight = 1 byte

Hence, virtualSize equals the size of the tx in byte, which can be used for the fee calculation.

However, @junderw mentioned about byteLength in https://github.com/bitcoinjs/bitcoinjs-lib/pull/811 and I wonder why it's different from virtualSize. Can anybody explain me the difference between virtualSize and byteLength?

I don't exactly understand the implementation of __byteLength:

https://github.com/bitcoinjs/bitcoinjs-lib/blob/9a8552acda9c1881c43b3b6a9b42fb6b46ebd424/src/transaction.js#L208-L219

takahser avatar Dec 04 '18 09:12 takahser

Please read my entire comment. 難しいとは思いますが、何卒宜しくお願い申し上げます。

How many byte a specific Transaction weighs after being mined.

This is unclear. I can not understand you. What do you need to use this for? Please explain by telling us your use case and not "what you want" because your use case might need something different than what you think you need.

Can anybody explain me the difference between virtualSize and byteLength?

I did. Please read my comment on the other issue. I explained what each one means... did you not read it? If you read it but did not understand it, why? https://github.com/bitcoinjs/bitcoinjs-lib/pull/811#issuecomment-444034886

For non-segwit transactions: virtualSize === weight / 4 === byteLength

For segwit transactions: virtualSize === weight / 4 === Math.ceil( byteLength - (((byteLength * 4) - weight) / 4)) (for non-segwit transactions, byteLength * 4 === weight so (byteLength * 4) - weight is 0, and 0/4 is 0. and byteLength - 0 is byteLength which is why it is the same.)

  1. byteLength is the number of bytes written on your disk when the transaction is saved to disk. (like your hard drive, SSD, thumbdrive, whatever)
  2. virtualSize is the number of bytes multiplied by a number that places less weight on witness data. (This is why it is called "segregated witness")
  3. weight units are a new unit that is used to constrain block size. (stripped block is still limited to 1000000 bytes, but also is limited to 4000000 weight units.)
  4. In general the only one we use daily for transaction creation is virtualSize since it is used for fee calculation.

https://medium.com/@jimmysong/understanding-segwit-block-size-fd901b87c9d4

Each transaction has a “weight” which is defined this way:

(tx size with witness data stripped) * 3 + (tx size)

Non-Segwit transactions have zero witness data, so the weight for a non-Segwit transaction is exactly 4 times the size. Segwit transactions have some witness data so the weight is going to be less than 4 times the size.

日本語も

https://bitcoincore.org/ja/segwit_wallet_dev/#transaction-fee-estimation

トランザクション手数料は他のトランザクションとvsizeを比較して見積もられます。(今までのサイズではなく)

junderw avatar Dec 04 '18 15:12 junderw

Also:

// version(4bytes) + locktime(4bytes) = 8... flag-byte and marker for segwit are one byte each, making 10
(hasWitnesses ? 10 : 8) + 
// The input/output counters are varint. The byte size of varint varies, this function returns that length.
varuint.encodingLength(this.ins.length) + 
varuint.encodingLength(this.outs.length) + 
// prevTxHash(32bytes) + prevOut(4bytes) + nSequence(4bytes) = 40 bytes
// Then we use varSliceSize to measure the size of the script plus a varint that holds the length.
this.ins.reduce(function (sum, input) { return sum + 40 + varSliceSize(input.script) }, 0) + 
// outputValue(8bytes) = 8... and the same varint + script counting function.
this.outs.reduce(function (sum, output) { return sum + 8 + varSliceSize(output.script) }, 0) + 
// If we have witnesses (is segwit) vectorSize returns the size of all pushdatas and
// their OP_CODEs along with the varints that describe the length of each witness stack.
(hasWitnesses ? this.ins.reduce(function (sum, input) { return sum + vectorSize(input.witness) }, 0) : 0) 

junderw avatar Dec 04 '18 15:12 junderw