github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/blockchain/compress.go (about)

     1  // Copyright (c) 2015-2016 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package blockchain
     7  
     8  import (
     9  	"github.com/BlockABC/godash/btcec"
    10  	"github.com/BlockABC/godash/txscript"
    11  )
    12  
    13  // -----------------------------------------------------------------------------
    14  // A variable length quantity (VLQ) is an encoding that uses an arbitrary number
    15  // of binary octets to represent an arbitrarily large integer.  The scheme
    16  // employs a most significant byte (MSB) base-128 encoding where the high bit in
    17  // each byte indicates whether or not the byte is the final one.  In addition,
    18  // to ensure there are no redundant encodings, an offset is subtracted every
    19  // time a group of 7 bits is shifted out.  Therefore each integer can be
    20  // represented in exactly one way, and each representation stands for exactly
    21  // one integer.
    22  //
    23  // Another nice property of this encoding is that it provides a compact
    24  // representation of values that are typically used to indicate sizes.  For
    25  // example, the values 0 - 127 are represented with a single byte, 128 - 16511
    26  // with two bytes, and 16512 - 2113663 with three bytes.
    27  //
    28  // While the encoding allows arbitrarily large integers, it is artificially
    29  // limited in this code to an unsigned 64-bit integer for efficiency purposes.
    30  //
    31  // Example encodings:
    32  //           0 -> [0x00]
    33  //         127 -> [0x7f]                 * Max 1-byte value
    34  //         128 -> [0x80 0x00]
    35  //         129 -> [0x80 0x01]
    36  //         255 -> [0x80 0x7f]
    37  //         256 -> [0x81 0x00]
    38  //       16511 -> [0xff 0x7f]            * Max 2-byte value
    39  //       16512 -> [0x80 0x80 0x00]
    40  //       32895 -> [0x80 0xff 0x7f]
    41  //     2113663 -> [0xff 0xff 0x7f]       * Max 3-byte value
    42  //   270549119 -> [0xff 0xff 0xff 0x7f]  * Max 4-byte value
    43  //      2^64-1 -> [0x80 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0x7f]
    44  //
    45  // References:
    46  //   https://en.wikipedia.org/wiki/Variable-length_quantity
    47  //   http://www.codecodex.com/wiki/Variable-Length_Integers
    48  // -----------------------------------------------------------------------------
    49  
    50  // serializeSizeVLQ returns the number of bytes it would take to serialize the
    51  // passed number as a variable-length quantity according to the format described
    52  // above.
    53  func serializeSizeVLQ(n uint64) int {
    54  	size := 1
    55  	for ; n > 0x7f; n = (n >> 7) - 1 {
    56  		size++
    57  	}
    58  
    59  	return size
    60  }
    61  
    62  // putVLQ serializes the provided number to a variable-length quantity according
    63  // to the format described above and returns the number of bytes of the encoded
    64  // value.  The result is placed directly into the passed byte slice which must
    65  // be at least large enough to handle the number of bytes returned by the
    66  // serializeSizeVLQ function or it will panic.
    67  func putVLQ(target []byte, n uint64) int {
    68  	offset := 0
    69  	for ; ; offset++ {
    70  		// The high bit is set when another byte follows.
    71  		highBitMask := byte(0x80)
    72  		if offset == 0 {
    73  			highBitMask = 0x00
    74  		}
    75  
    76  		target[offset] = byte(n&0x7f) | highBitMask
    77  		if n <= 0x7f {
    78  			break
    79  		}
    80  		n = (n >> 7) - 1
    81  	}
    82  
    83  	// Reverse the bytes so it is MSB-encoded.
    84  	for i, j := 0, offset; i < j; i, j = i+1, j-1 {
    85  		target[i], target[j] = target[j], target[i]
    86  	}
    87  
    88  	return offset + 1
    89  }
    90  
    91  // deserializeVLQ deserializes the provided variable-length quantity according
    92  // to the format described above.  It also returns the number of bytes
    93  // deserialized.
    94  func deserializeVLQ(serialized []byte) (uint64, int) {
    95  	var n uint64
    96  	var size int
    97  	for _, val := range serialized {
    98  		size++
    99  		n = (n << 7) | uint64(val&0x7f)
   100  		if val&0x80 != 0x80 {
   101  			break
   102  		}
   103  		n++
   104  	}
   105  
   106  	return n, size
   107  }
   108  
   109  // -----------------------------------------------------------------------------
   110  // In order to reduce the size of stored scripts, a domain specific compression
   111  // algorithm is used which recognizes standard scripts and stores them using
   112  // less bytes than the original script.  The compression algorithm used here was
   113  // obtained from Bitcoin Core, so all credits for the algorithm go to it.
   114  //
   115  // The general serialized format is:
   116  //
   117  //   <script size or type><script data>
   118  //
   119  //   Field                 Type     Size
   120  //   script size or type   VLQ      variable
   121  //   script data           []byte   variable
   122  //
   123  // The specific serialized format for each recognized standard script is:
   124  //
   125  // - Pay-to-pubkey-hash: (21 bytes) - <0><20-byte pubkey hash>
   126  // - Pay-to-script-hash: (21 bytes) - <1><20-byte script hash>
   127  // - Pay-to-pubkey**:    (33 bytes) - <2, 3, 4, or 5><32-byte pubkey X value>
   128  //   2, 3 = compressed pubkey with bit 0 specifying the y coordinate to use
   129  //   4, 5 = uncompressed pubkey with bit 0 specifying the y coordinate to use
   130  //   ** Only valid public keys starting with 0x02, 0x03, and 0x04 are supported.
   131  //
   132  // Any scripts which are not recognized as one of the aforementioned standard
   133  // scripts are encoded using the general serialized format and encode the script
   134  // size as the sum of the actual size of the script and the number of special
   135  // cases.
   136  // -----------------------------------------------------------------------------
   137  
   138  // The following constants specify the special constants used to identify a
   139  // special script type in the domain-specific compressed script encoding.
   140  //
   141  // NOTE: This section specifically does not use iota since these values are
   142  // serialized and must be stable for long-term storage.
   143  const (
   144  	// cstPayToPubKeyHash identifies a compressed pay-to-pubkey-hash script.
   145  	cstPayToPubKeyHash = 0
   146  
   147  	// cstPayToScriptHash identifies a compressed pay-to-script-hash script.
   148  	cstPayToScriptHash = 1
   149  
   150  	// cstPayToPubKeyComp2 identifies a compressed pay-to-pubkey script to
   151  	// a compressed pubkey.  Bit 0 specifies which y-coordinate to use
   152  	// to reconstruct the full uncompressed pubkey.
   153  	cstPayToPubKeyComp2 = 2
   154  
   155  	// cstPayToPubKeyComp3 identifies a compressed pay-to-pubkey script to
   156  	// a compressed pubkey.  Bit 0 specifies which y-coordinate to use
   157  	// to reconstruct the full uncompressed pubkey.
   158  	cstPayToPubKeyComp3 = 3
   159  
   160  	// cstPayToPubKeyUncomp4 identifies a compressed pay-to-pubkey script to
   161  	// an uncompressed pubkey.  Bit 0 specifies which y-coordinate to use
   162  	// to reconstruct the full uncompressed pubkey.
   163  	cstPayToPubKeyUncomp4 = 4
   164  
   165  	// cstPayToPubKeyUncomp5 identifies a compressed pay-to-pubkey script to
   166  	// an uncompressed pubkey.  Bit 0 specifies which y-coordinate to use
   167  	// to reconstruct the full uncompressed pubkey.
   168  	cstPayToPubKeyUncomp5 = 5
   169  
   170  	// numSpecialScripts is the number of special scripts recognized by the
   171  	// domain-specific script compression algorithm.
   172  	numSpecialScripts = 6
   173  )
   174  
   175  // isPubKeyHash returns whether or not the passed public key script is a
   176  // standard pay-to-pubkey-hash script along with the pubkey hash it is paying to
   177  // if it is.
   178  func isPubKeyHash(script []byte) (bool, []byte) {
   179  	if len(script) == 25 && script[0] == txscript.OP_DUP &&
   180  		script[1] == txscript.OP_HASH160 &&
   181  		script[2] == txscript.OP_DATA_20 &&
   182  		script[23] == txscript.OP_EQUALVERIFY &&
   183  		script[24] == txscript.OP_CHECKSIG {
   184  
   185  		return true, script[3:23]
   186  	}
   187  
   188  	return false, nil
   189  }
   190  
   191  // isScriptHash returns whether or not the passed public key script is a
   192  // standard pay-to-script-hash script along with the script hash it is paying to
   193  // if it is.
   194  func isScriptHash(script []byte) (bool, []byte) {
   195  	if len(script) == 23 && script[0] == txscript.OP_HASH160 &&
   196  		script[1] == txscript.OP_DATA_20 &&
   197  		script[22] == txscript.OP_EQUAL {
   198  
   199  		return true, script[2:22]
   200  	}
   201  
   202  	return false, nil
   203  }
   204  
   205  // isPubKey returns whether or not the passed public key script is a standard
   206  // pay-to-pubkey script that pays to a valid compressed or uncompressed public
   207  // key along with the serialized pubkey it is paying to if it is.
   208  //
   209  // NOTE: This function ensures the public key is actually valid since the
   210  // compression algorithm requires valid pubkeys.  It does not support hybrid
   211  // pubkeys.  This means that even if the script has the correct form for a
   212  // pay-to-pubkey script, this function will only return true when it is paying
   213  // to a valid compressed or uncompressed pubkey.
   214  func isPubKey(script []byte) (bool, []byte) {
   215  	// Pay-to-compressed-pubkey script.
   216  	if len(script) == 35 && script[0] == txscript.OP_DATA_33 &&
   217  		script[34] == txscript.OP_CHECKSIG && (script[1] == 0x02 ||
   218  		script[1] == 0x03) {
   219  
   220  		// Ensure the public key is valid.
   221  		serializedPubKey := script[1:34]
   222  		_, err := btcec.ParsePubKey(serializedPubKey, btcec.S256())
   223  		if err == nil {
   224  			return true, serializedPubKey
   225  		}
   226  	}
   227  
   228  	// Pay-to-uncompressed-pubkey script.
   229  	if len(script) == 67 && script[0] == txscript.OP_DATA_65 &&
   230  		script[66] == txscript.OP_CHECKSIG && script[1] == 0x04 {
   231  
   232  		// Ensure the public key is valid.
   233  		serializedPubKey := script[1:66]
   234  		_, err := btcec.ParsePubKey(serializedPubKey, btcec.S256())
   235  		if err == nil {
   236  			return true, serializedPubKey
   237  		}
   238  	}
   239  
   240  	return false, nil
   241  }
   242  
   243  // compressedScriptSize returns the number of bytes the passed script would take
   244  // when encoded with the domain specific compression algorithm described above.
   245  func compressedScriptSize(pkScript []byte, version int32) int {
   246  	// Pay-to-pubkey-hash script.
   247  	if valid, _ := isPubKeyHash(pkScript); valid {
   248  		return 21
   249  	}
   250  
   251  	// Pay-to-script-hash script.
   252  	if valid, _ := isScriptHash(pkScript); valid {
   253  		return 21
   254  	}
   255  
   256  	// Pay-to-pubkey (compressed or uncompressed) script.
   257  	if valid, _ := isPubKey(pkScript); valid {
   258  		return 33
   259  	}
   260  
   261  	// When none of the above special cases apply, encode the script as is
   262  	// preceded by the sum of its size and the number of special cases
   263  	// encoded as a variable length quantity.
   264  	return serializeSizeVLQ(uint64(len(pkScript)+numSpecialScripts)) +
   265  		len(pkScript)
   266  }
   267  
   268  // decodeCompressedScriptSize treats the passed serialized bytes as a compressed
   269  // script, possibly followed by other data, and returns the number of bytes it
   270  // occupies taking into account the special encoding of the script size by the
   271  // domain specific compression algorithm described above.
   272  func decodeCompressedScriptSize(serialized []byte, version int32) int {
   273  	scriptSize, bytesRead := deserializeVLQ(serialized)
   274  	if bytesRead == 0 {
   275  		return 0
   276  	}
   277  
   278  	switch scriptSize {
   279  	case cstPayToPubKeyHash:
   280  		return 21
   281  
   282  	case cstPayToScriptHash:
   283  		return 21
   284  
   285  	case cstPayToPubKeyComp2, cstPayToPubKeyComp3, cstPayToPubKeyUncomp4,
   286  		cstPayToPubKeyUncomp5:
   287  		return 33
   288  	}
   289  
   290  	scriptSize -= numSpecialScripts
   291  	scriptSize += uint64(bytesRead)
   292  	return int(scriptSize)
   293  }
   294  
   295  // putCompressedScript compresses the passed script according to the domain
   296  // specific compression algorithm described above directly into the passed
   297  // target byte slice.  The target byte slice must be at least large enough to
   298  // handle the number of bytes returned by the compressedScriptSize function or
   299  // it will panic.
   300  func putCompressedScript(target, pkScript []byte, version int32) int {
   301  	// Pay-to-pubkey-hash script.
   302  	if valid, hash := isPubKeyHash(pkScript); valid {
   303  		target[0] = cstPayToPubKeyHash
   304  		copy(target[1:21], hash)
   305  		return 21
   306  	}
   307  
   308  	// Pay-to-script-hash script.
   309  	if valid, hash := isScriptHash(pkScript); valid {
   310  		target[0] = cstPayToScriptHash
   311  		copy(target[1:21], hash)
   312  		return 21
   313  	}
   314  
   315  	// Pay-to-pubkey (compressed or uncompressed) script.
   316  	if valid, serializedPubKey := isPubKey(pkScript); valid {
   317  		pubKeyFormat := serializedPubKey[0]
   318  		switch pubKeyFormat {
   319  		case 0x02, 0x03:
   320  			target[0] = pubKeyFormat
   321  			copy(target[1:33], serializedPubKey[1:33])
   322  			return 33
   323  		case 0x04:
   324  			// Encode the oddness of the serialized pubkey into the
   325  			// compressed script type.
   326  			target[0] = pubKeyFormat | (serializedPubKey[64] & 0x01)
   327  			copy(target[1:33], serializedPubKey[1:33])
   328  			return 33
   329  		}
   330  	}
   331  
   332  	// When none of the above special cases apply, encode the unmodified
   333  	// script preceded by the sum of its size and the number of special
   334  	// cases encoded as a variable length quantity.
   335  	encodedSize := uint64(len(pkScript) + numSpecialScripts)
   336  	vlqSizeLen := putVLQ(target, encodedSize)
   337  	copy(target[vlqSizeLen:], pkScript)
   338  	return vlqSizeLen + len(pkScript)
   339  }
   340  
   341  // decompressScript returns the original script obtained by decompressing the
   342  // passed compressed script according to the domain specific compression
   343  // algorithm described above.
   344  //
   345  // NOTE: The script parameter must already have been proven to be long enough
   346  // to contain the number of bytes returned by decodeCompressedScriptSize or it
   347  // will panic.  This is acceptable since it is only an internal function.
   348  func decompressScript(compressedPkScript []byte, version int32) []byte {
   349  	// In practice this function will not be called with a zero-length or
   350  	// nil script since the nil script encoding includes the length, however
   351  	// the code below assumes the length exists, so just return nil now if
   352  	// the function ever ends up being called with a nil script in the
   353  	// future.
   354  	if len(compressedPkScript) == 0 {
   355  		return nil
   356  	}
   357  
   358  	// Decode the script size and examine it for the special cases.
   359  	encodedScriptSize, bytesRead := deserializeVLQ(compressedPkScript)
   360  	switch encodedScriptSize {
   361  	// Pay-to-pubkey-hash script.  The resulting script is:
   362  	// <OP_DUP><OP_HASH160><20 byte hash><OP_EQUALVERIFY><OP_CHECKSIG>
   363  	case cstPayToPubKeyHash:
   364  		pkScript := make([]byte, 25)
   365  		pkScript[0] = txscript.OP_DUP
   366  		pkScript[1] = txscript.OP_HASH160
   367  		pkScript[2] = txscript.OP_DATA_20
   368  		copy(pkScript[3:], compressedPkScript[bytesRead:bytesRead+20])
   369  		pkScript[23] = txscript.OP_EQUALVERIFY
   370  		pkScript[24] = txscript.OP_CHECKSIG
   371  		return pkScript
   372  
   373  	// Pay-to-script-hash script.  The resulting script is:
   374  	// <OP_HASH160><20 byte script hash><OP_EQUAL>
   375  	case cstPayToScriptHash:
   376  		pkScript := make([]byte, 23)
   377  		pkScript[0] = txscript.OP_HASH160
   378  		pkScript[1] = txscript.OP_DATA_20
   379  		copy(pkScript[2:], compressedPkScript[bytesRead:bytesRead+20])
   380  		pkScript[22] = txscript.OP_EQUAL
   381  		return pkScript
   382  
   383  	// Pay-to-compressed-pubkey script.  The resulting script is:
   384  	// <OP_DATA_33><33 byte compressed pubkey><OP_CHECKSIG>
   385  	case cstPayToPubKeyComp2, cstPayToPubKeyComp3:
   386  		pkScript := make([]byte, 35)
   387  		pkScript[0] = txscript.OP_DATA_33
   388  		pkScript[1] = byte(encodedScriptSize)
   389  		copy(pkScript[2:], compressedPkScript[bytesRead:bytesRead+32])
   390  		pkScript[34] = txscript.OP_CHECKSIG
   391  		return pkScript
   392  
   393  	// Pay-to-uncompressed-pubkey script.  The resulting script is:
   394  	// <OP_DATA_65><65 byte uncompressed pubkey><OP_CHECKSIG>
   395  	case cstPayToPubKeyUncomp4, cstPayToPubKeyUncomp5:
   396  		// Change the leading byte to the appropriate compressed pubkey
   397  		// identifier (0x02 or 0x03) so it can be decoded as a
   398  		// compressed pubkey.  This really should never fail since the
   399  		// encoding ensures it is valid before compressing to this type.
   400  		compressedKey := make([]byte, 33)
   401  		compressedKey[0] = byte(encodedScriptSize - 2)
   402  		copy(compressedKey[1:], compressedPkScript[1:])
   403  		key, err := btcec.ParsePubKey(compressedKey, btcec.S256())
   404  		if err != nil {
   405  			return nil
   406  		}
   407  
   408  		pkScript := make([]byte, 67)
   409  		pkScript[0] = txscript.OP_DATA_65
   410  		copy(pkScript[1:], key.SerializeUncompressed())
   411  		pkScript[66] = txscript.OP_CHECKSIG
   412  		return pkScript
   413  	}
   414  
   415  	// When none of the special cases apply, the script was encoded using
   416  	// the general format, so reduce the script size by the number of
   417  	// special cases and return the unmodified script.
   418  	scriptSize := int(encodedScriptSize - numSpecialScripts)
   419  	pkScript := make([]byte, scriptSize)
   420  	copy(pkScript, compressedPkScript[bytesRead:bytesRead+scriptSize])
   421  	return pkScript
   422  }
   423  
   424  // -----------------------------------------------------------------------------
   425  // In order to reduce the size of stored amounts, a domain specific compression
   426  // algorithm is used which relies on there typically being a lot of zeroes at
   427  // end of the amounts.  The compression algorithm used here was obtained from
   428  // Bitcoin Core, so all credits for the algorithm go to it.
   429  //
   430  // While this is simply exchanging one uint64 for another, the resulting value
   431  // for typical amounts has a much smaller magnitude which results in fewer bytes
   432  // when encoded as variable length quantity.  For example, consider the amount
   433  // of 0.1 BTC which is 10000000 satoshi.  Encoding 10000000 as a VLQ would take
   434  // 4 bytes while encoding the compressed value of 8 as a VLQ only takes 1 byte.
   435  //
   436  // Essentially the compression is achieved by splitting the value into an
   437  // exponent in the range [0-9] and a digit in the range [1-9], when possible,
   438  // and encoding them in a way that can be decoded.  More specifically, the
   439  // encoding is as follows:
   440  // - 0 is 0
   441  // - Find the exponent, e, as the largest power of 10 that evenly divides the
   442  //   value up to a maximum of 9
   443  // - When e < 9, the final digit can't be 0 so store it as d and remove it by
   444  //   dividing the value by 10 (call the result n).  The encoded value is thus:
   445  //   1 + 10*(9*n + d-1) + e
   446  // - When e==9, the only thing known is the amount is not 0.  The encoded value
   447  //   is thus:
   448  //   1 + 10*(n-1) + e   ==   10 + 10*(n-1)
   449  //
   450  // Example encodings:
   451  // (The numbers in parenthesis are the number of bytes when serialized as a VLQ)
   452  //            0 (1) -> 0        (1)           *  0.00000000 BTC
   453  //         1000 (2) -> 4        (1)           *  0.00001000 BTC
   454  //        10000 (2) -> 5        (1)           *  0.00010000 BTC
   455  //     12345678 (4) -> 111111101(4)           *  0.12345678 BTC
   456  //     50000000 (4) -> 47       (1)           *  0.50000000 BTC
   457  //    100000000 (4) -> 9        (1)           *  1.00000000 BTC
   458  //    500000000 (5) -> 49       (1)           *  5.00000000 BTC
   459  //   1000000000 (5) -> 10       (1)           * 10.00000000 BTC
   460  // -----------------------------------------------------------------------------
   461  
   462  // compressTxOutAmount compresses the passed amount according to the domain
   463  // specific compression algorithm described above.
   464  func compressTxOutAmount(amount uint64) uint64 {
   465  	// No need to do any work if it's zero.
   466  	if amount == 0 {
   467  		return 0
   468  	}
   469  
   470  	// Find the largest power of 10 (max of 9) that evenly divides the
   471  	// value.
   472  	exponent := uint64(0)
   473  	for amount%10 == 0 && exponent < 9 {
   474  		amount /= 10
   475  		exponent++
   476  	}
   477  
   478  	// The compressed result for exponents less than 9 is:
   479  	// 1 + 10*(9*n + d-1) + e
   480  	if exponent < 9 {
   481  		lastDigit := amount % 10
   482  		amount /= 10
   483  		return 1 + 10*(9*amount+lastDigit-1) + exponent
   484  	}
   485  
   486  	// The compressed result for an exponent of 9 is:
   487  	// 1 + 10*(n-1) + e   ==   10 + 10*(n-1)
   488  	return 10 + 10*(amount-1)
   489  }
   490  
   491  // decompressTxOutAmount returns the original amount the passed compressed
   492  // amount represents according to the domain specific compression algorithm
   493  // described above.
   494  func decompressTxOutAmount(amount uint64) uint64 {
   495  	// No need to do any work if it's zero.
   496  	if amount == 0 {
   497  		return 0
   498  	}
   499  
   500  	// The decompressed amount is either of the following two equations:
   501  	// x = 1 + 10*(9*n + d - 1) + e
   502  	// x = 1 + 10*(n - 1)       + 9
   503  	amount--
   504  
   505  	// The decompressed amount is now one of the following two equations:
   506  	// x = 10*(9*n + d - 1) + e
   507  	// x = 10*(n - 1)       + 9
   508  	exponent := amount % 10
   509  	amount /= 10
   510  
   511  	// The decompressed amount is now one of the following two equations:
   512  	// x = 9*n + d - 1  | where e < 9
   513  	// x = n - 1        | where e = 9
   514  	n := uint64(0)
   515  	if exponent < 9 {
   516  		lastDigit := amount%9 + 1
   517  		amount /= 9
   518  		n = amount*10 + lastDigit
   519  	} else {
   520  		n = amount + 1
   521  	}
   522  
   523  	// Apply the exponent.
   524  	for ; exponent > 0; exponent-- {
   525  		n *= 10
   526  	}
   527  
   528  	return n
   529  }
   530  
   531  // -----------------------------------------------------------------------------
   532  // Compressed transaction outputs consist of an amount and a public key script
   533  // both compressed using the domain specific compression algorithms previously
   534  // described.
   535  //
   536  // The serialized format is:
   537  //
   538  //   <compressed amount><compressed script>
   539  //
   540  //   Field                 Type     Size
   541  //     compressed amount   VLQ      variable
   542  //     compressed script   []byte   variable
   543  // -----------------------------------------------------------------------------
   544  
   545  // compressedTxOutSize returns the number of bytes the passed transaction output
   546  // fields would take when encoded with the format described above.  The
   547  // preCompressed flag indicates the provided amount and script are already
   548  // compressed.  This is useful since loaded utxo entries are not decompressed
   549  // until the output is accessed.
   550  func compressedTxOutSize(amount uint64, pkScript []byte, version int32, preCompressed bool) int {
   551  	if preCompressed {
   552  		return serializeSizeVLQ(amount) + len(pkScript)
   553  	}
   554  
   555  	return serializeSizeVLQ(compressTxOutAmount(amount)) +
   556  		compressedScriptSize(pkScript, version)
   557  }
   558  
   559  // putCompressedTxOut potentially compresses the passed amount and script
   560  // according to their domain specific compression algorithms and encodes them
   561  // directly into the passed target byte slice with the format described above.
   562  // The preCompressed flag indicates the provided amount and script are already
   563  // compressed in which case the values are not modified.  This is useful since
   564  // loaded utxo entries are not decompressed until the output is accessed.  The
   565  // target byte slice must be at least large enough to handle the number of bytes
   566  // returned by the compressedTxOutSize function or it will panic.
   567  func putCompressedTxOut(target []byte, amount uint64, pkScript []byte, version int32, preCompressed bool) int {
   568  	if preCompressed {
   569  		offset := putVLQ(target, amount)
   570  		copy(target[offset:], pkScript)
   571  		return offset + len(pkScript)
   572  	}
   573  
   574  	offset := putVLQ(target, compressTxOutAmount(amount))
   575  	offset += putCompressedScript(target[offset:], pkScript, version)
   576  	return offset
   577  }
   578  
   579  // decodeCompressedTxOut decodes the passed compressed txout, possibly followed
   580  // by other data, into its compressed amount and compressed script and returns
   581  // them along with the number of bytes they occupied.
   582  func decodeCompressedTxOut(serialized []byte, version int32) (uint64, []byte, int, error) {
   583  	// Deserialize the compressed amount and ensure there are bytes
   584  	// remaining for the compressed script.
   585  	compressedAmount, bytesRead := deserializeVLQ(serialized)
   586  	if bytesRead >= len(serialized) {
   587  		return 0, nil, bytesRead, errDeserialize("unexpected end of " +
   588  			"data after compressed amount")
   589  	}
   590  
   591  	// Decode the compressed script size and ensure there are enough bytes
   592  	// left in the slice for it.
   593  	scriptSize := decodeCompressedScriptSize(serialized[bytesRead:], version)
   594  	if len(serialized[bytesRead:]) < scriptSize {
   595  		return 0, nil, bytesRead, errDeserialize("unexpected end of " +
   596  			"data after script size")
   597  	}
   598  
   599  	// Make a copy of the compressed script so the original serialized data
   600  	// can be released as soon as possible.
   601  	compressedScript := make([]byte, scriptSize)
   602  	copy(compressedScript, serialized[bytesRead:bytesRead+scriptSize])
   603  	return compressedAmount, compressedScript, bytesRead + scriptSize, nil
   604  }