github.com/decred/dcrd/blockchain@v1.2.1/compress.go (about)

     1  // Copyright (c) 2015-2016 The btcsuite developers
     2  // Copyright (c) 2015-2018 The Decred 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  	"fmt"
    10  
    11  	"github.com/decred/dcrd/blockchain/stake"
    12  	"github.com/decred/dcrd/dcrec/secp256k1"
    13  	"github.com/decred/dcrd/txscript"
    14  )
    15  
    16  // currentCompressionVersion is the current script compression version of the
    17  // database.
    18  const currentCompressionVersion = 1
    19  
    20  // -----------------------------------------------------------------------------
    21  // A variable length quantity (VLQ) is an encoding that uses an arbitrary number
    22  // of binary octets to represent an arbitrarily large integer.  The scheme
    23  // employs a most significant byte (MSB) base-128 encoding where the high bit in
    24  // each byte indicates whether or not the byte is the final one.  In addition,
    25  // to ensure there are no redundant encodings, an offset is subtracted every
    26  // time a group of 7 bits is shifted out.  Therefore each integer can be
    27  // represented in exactly one way, and each representation stands for exactly
    28  // one integer.
    29  //
    30  // Another nice property of this encoding is that it provides a compact
    31  // representation of values that are typically used to indicate sizes.  For
    32  // example, the values 0 - 127 are represented with a single byte, 128 - 16511
    33  // with two bytes, and 16512 - 2113663 with three bytes.
    34  //
    35  // While the encoding allows arbitrarily large integers, it is artificially
    36  // limited in this code to an unsigned 64-bit integer for efficiency purposes.
    37  //
    38  // Example encodings:
    39  //           0 -> [0x00]
    40  //         127 -> [0x7f]                 * Max 1-byte value
    41  //         128 -> [0x80 0x00]
    42  //         129 -> [0x80 0x01]
    43  //         255 -> [0x80 0x7f]
    44  //         256 -> [0x81 0x00]
    45  //       16511 -> [0xff 0x7f]            * Max 2-byte value
    46  //       16512 -> [0x80 0x80 0x00]
    47  //       32895 -> [0x80 0xff 0x7f]
    48  //     2113663 -> [0xff 0xff 0x7f]       * Max 3-byte value
    49  //   270549119 -> [0xff 0xff 0xff 0x7f]  * Max 4-byte value
    50  //      2^64-1 -> [0x80 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0x7f]
    51  //
    52  // References:
    53  //   https://en.wikipedia.org/wiki/Variable-length_quantity
    54  //   http://www.codecodex.com/wiki/Variable-Length_Integers
    55  // -----------------------------------------------------------------------------
    56  
    57  // serializeSizeVLQ returns the number of bytes it would take to serialize the
    58  // passed number as a variable-length quantity according to the format described
    59  // above.
    60  func serializeSizeVLQ(n uint64) int {
    61  	size := 1
    62  	for ; n > 0x7f; n = (n >> 7) - 1 {
    63  		size++
    64  	}
    65  
    66  	return size
    67  }
    68  
    69  // putVLQ serializes the provided number to a variable-length quantity according
    70  // to the format described above and returns the number of bytes of the encoded
    71  // value.  The result is placed directly into the passed byte slice which must
    72  // be at least large enough to handle the number of bytes returned by the
    73  // serializeSizeVLQ function or it will panic.
    74  func putVLQ(target []byte, n uint64) int {
    75  	offset := 0
    76  	for ; ; offset++ {
    77  		// The high bit is set when another byte follows.
    78  		highBitMask := byte(0x80)
    79  		if offset == 0 {
    80  			highBitMask = 0x00
    81  		}
    82  
    83  		target[offset] = byte(n&0x7f) | highBitMask
    84  		if n <= 0x7f {
    85  			break
    86  		}
    87  		n = (n >> 7) - 1
    88  	}
    89  
    90  	// Reverse the bytes so it is MSB-encoded.
    91  	for i, j := 0, offset; i < j; i, j = i+1, j-1 {
    92  		target[i], target[j] = target[j], target[i]
    93  	}
    94  
    95  	return offset + 1
    96  }
    97  
    98  // deserializeVLQ deserializes the provided variable-length quantity according
    99  // to the format described above.  It also returns the number of bytes
   100  // deserialized.
   101  func deserializeVLQ(serialized []byte) (uint64, int) {
   102  	var n uint64
   103  	var size int
   104  	for _, val := range serialized {
   105  		size++
   106  		n = (n << 7) | uint64(val&0x7f)
   107  		if val&0x80 != 0x80 {
   108  			break
   109  		}
   110  		n++
   111  	}
   112  
   113  	return n, size
   114  }
   115  
   116  // -----------------------------------------------------------------------------
   117  // In order to reduce the size of stored scripts, a domain specific compression
   118  // algorithm is used which recognizes standard scripts and stores them using
   119  // less bytes than the original script.  The compression algorithm used here was
   120  // obtained from Bitcoin Core, so all credits for the algorithm go to it.
   121  //
   122  // The general serialized format is:
   123  //
   124  //   <script size or type><script data>
   125  //
   126  //   Field                 Type     Size
   127  //   script size or type   VLQ      variable
   128  //   script data           []byte   variable
   129  //
   130  // The specific serialized format for each recognized standard script is:
   131  //
   132  // - Pay-to-pubkey-hash: (21 bytes) - <0><20-byte pubkey hash>
   133  // - Pay-to-script-hash: (21 bytes) - <1><20-byte script hash>
   134  // - Pay-to-pubkey**:    (33 bytes) - <2, 3, 4, or 5><32-byte pubkey X value>
   135  //   2, 3 = compressed pubkey with bit 0 specifying the y coordinate to use
   136  //   4, 5 = uncompressed pubkey with bit 0 specifying the y coordinate to use
   137  //   ** Only valid public keys starting with 0x02, 0x03, and 0x04 are supported.
   138  //
   139  // Any scripts which are not recognized as one of the aforementioned standard
   140  // scripts are encoded using the general serialized format and encode the script
   141  // size as the sum of the actual size of the script and the number of special
   142  // cases.
   143  // -----------------------------------------------------------------------------
   144  
   145  // The following constants specify the special constants used to identify a
   146  // special script type in the domain-specific compressed script encoding.
   147  //
   148  // NOTE: This section specifically does not use iota since these values are
   149  // serialized and must be stable for long-term storage.
   150  const (
   151  	// cstPayToPubKeyHash identifies a compressed pay-to-pubkey-hash script.
   152  	cstPayToPubKeyHash = 0
   153  
   154  	// cstPayToScriptHash identifies a compressed pay-to-script-hash script.
   155  	cstPayToScriptHash = 1
   156  
   157  	// cstPayToPubKeyCompEven identifies a compressed pay-to-pubkey script to
   158  	// a compressed pubkey whose y coordinate is not odd.
   159  	cstPayToPubKeyCompEven = 2
   160  
   161  	// cstPayToPubKeyCompOdd identifies a compressed pay-to-pubkey script to
   162  	// a compressed pubkey whose y coordinate is odd.
   163  	cstPayToPubKeyCompOdd = 3
   164  
   165  	// cstPayToPubKeyUncompEven identifies a compressed pay-to-pubkey script to
   166  	// an uncompressed pubkey whose y coordinate is not odd when compressed.
   167  	cstPayToPubKeyUncompEven = 4
   168  
   169  	// cstPayToPubKeyUncompOdd identifies a compressed pay-to-pubkey script to
   170  	// an uncompressed pubkey whose y coordinate is odd when compressed.
   171  	cstPayToPubKeyUncompOdd = 5
   172  
   173  	// numSpecialScripts is the number of special scripts possibly recognized
   174  	// by the domain-specific script compression algorithm. It is one more
   175  	// than half the number required to overflow a single byte in VLQ format
   176  	// (127). All scripts prefixed 64 and higher for their size are considered
   177  	// uncompressed scripts that are stored uncompressed. Because only 5
   178  	// special script types are currently stored by Decred, there is a large
   179  	// amount of room for future upgrades to the compression algorithm with
   180  	// scripts that are common, such as those for the staking system.
   181  	numSpecialScripts = 64
   182  )
   183  
   184  // extractPubKeyHash extracts a pubkey hash that is being paid from the passed
   185  // public key script if it is a standard pay-to-pubkey-hash script.  It will
   186  // return nil otherwise.
   187  func extractPubKeyHash(script []byte) []byte {
   188  	if len(script) == 25 && script[0] == txscript.OP_DUP &&
   189  		script[1] == txscript.OP_HASH160 &&
   190  		script[2] == txscript.OP_DATA_20 &&
   191  		script[23] == txscript.OP_EQUALVERIFY &&
   192  		script[24] == txscript.OP_CHECKSIG {
   193  
   194  		return script[3:23]
   195  	}
   196  
   197  	return nil
   198  }
   199  
   200  // isPubKeyHash returns whether or not the passed public key script is a
   201  // standard pay-to-pubkey-hash script.
   202  func isPubKeyHash(script []byte) bool {
   203  	return extractPubKeyHash(script) != nil
   204  }
   205  
   206  // extractScriptHash extracts a script hash that is being paid from the passed
   207  // public key script if it is a standard pay-to-script-hash script.  It will
   208  // return nil otherwise.
   209  func extractScriptHash(script []byte) []byte {
   210  	if len(script) == 23 && script[0] == txscript.OP_HASH160 &&
   211  		script[1] == txscript.OP_DATA_20 &&
   212  		script[22] == txscript.OP_EQUAL {
   213  
   214  		return script[2:22]
   215  	}
   216  
   217  	return nil
   218  }
   219  
   220  // isScriptHash returns whether or not the passed public key script is a
   221  // standard pay-to-script-hash script.
   222  func isScriptHash(script []byte) bool {
   223  	return extractScriptHash(script) != nil
   224  }
   225  
   226  // isPubKey returns whether or not the passed public key script is a standard
   227  // pay-to-pubkey script that pays to a valid compressed or uncompressed public
   228  // key along with the serialized pubkey it is paying to if it is.
   229  //
   230  // NOTE: This function ensures the public key is actually valid since the
   231  // compression algorithm requires valid pubkeys.  It does not support hybrid
   232  // pubkeys.  This means that even if the script has the correct form for a
   233  // pay-to-pubkey script, this function will only return true when it is paying
   234  // to a valid compressed or uncompressed pubkey.
   235  func isPubKey(script []byte) (bool, []byte) {
   236  	// Pay-to-compressed-pubkey script.
   237  	if len(script) == 35 && script[0] == txscript.OP_DATA_33 &&
   238  		script[34] == txscript.OP_CHECKSIG && (script[1] == 0x02 ||
   239  		script[1] == 0x03) {
   240  
   241  		// Ensure the public key is valid.
   242  		serializedPubKey := script[1:34]
   243  		_, err := secp256k1.ParsePubKey(serializedPubKey)
   244  		if err == nil {
   245  			return true, serializedPubKey
   246  		}
   247  	}
   248  
   249  	// Pay-to-uncompressed-pubkey script.
   250  	if len(script) == 67 && script[0] == txscript.OP_DATA_65 &&
   251  		script[66] == txscript.OP_CHECKSIG && script[1] == 0x04 {
   252  
   253  		// Ensure the public key is valid.
   254  		serializedPubKey := script[1:66]
   255  		_, err := secp256k1.ParsePubKey(serializedPubKey)
   256  		if err == nil {
   257  			return true, serializedPubKey
   258  		}
   259  	}
   260  
   261  	return false, nil
   262  }
   263  
   264  // compressedScriptSize returns the number of bytes the passed script would take
   265  // when encoded with the domain specific compression algorithm described above.
   266  func compressedScriptSize(scriptVersion uint16, pkScript []byte,
   267  	compressionVersion uint32) int {
   268  	// Pay-to-pubkey-hash or pay-to-script-hash script.
   269  	if isPubKeyHash(pkScript) || isScriptHash(pkScript) {
   270  		return 21
   271  	}
   272  
   273  	// Pay-to-pubkey (compressed or uncompressed) script.
   274  	if valid, _ := isPubKey(pkScript); valid {
   275  		return 33
   276  	}
   277  
   278  	// When none of the above special cases apply, encode the script as is
   279  	// preceded by the sum of its size and the number of special cases
   280  	// encoded as a variable length quantity.
   281  	return serializeSizeVLQ(uint64(len(pkScript)+numSpecialScripts)) +
   282  		len(pkScript)
   283  }
   284  
   285  // decodeCompressedScriptSize treats the passed serialized bytes as a compressed
   286  // script, possibly followed by other data, and returns the number of bytes it
   287  // occupies taking into account the special encoding of the script size by the
   288  // domain specific compression algorithm described above.
   289  func decodeCompressedScriptSize(serialized []byte, compressionVersion uint32) int {
   290  	scriptSize, bytesRead := deserializeVLQ(serialized)
   291  	if bytesRead == 0 {
   292  		return 0
   293  	}
   294  
   295  	switch scriptSize {
   296  	case cstPayToPubKeyHash:
   297  		return 21
   298  
   299  	case cstPayToScriptHash:
   300  		return 21
   301  
   302  	case cstPayToPubKeyCompEven, cstPayToPubKeyCompOdd,
   303  		cstPayToPubKeyUncompEven, cstPayToPubKeyUncompOdd:
   304  		return 33
   305  	}
   306  
   307  	scriptSize -= numSpecialScripts
   308  	scriptSize += uint64(bytesRead)
   309  	return int(scriptSize)
   310  }
   311  
   312  // putCompressedScript compresses the passed script according to the domain
   313  // specific compression algorithm described above directly into the passed
   314  // target byte slice.  The target byte slice must be at least large enough to
   315  // handle the number of bytes returned by the compressedScriptSize function or
   316  // it will panic.
   317  func putCompressedScript(target []byte, scriptVersion uint16, pkScript []byte,
   318  	compressionVersion uint32) int {
   319  	if len(target) == 0 {
   320  		target[0] = 0x00
   321  		return 1
   322  	}
   323  
   324  	// Pay-to-pubkey-hash script.
   325  	if hash := extractPubKeyHash(pkScript); hash != nil {
   326  		target[0] = cstPayToPubKeyHash
   327  		copy(target[1:21], hash)
   328  		return 21
   329  	}
   330  
   331  	// Pay-to-script-hash script.
   332  	if hash := extractScriptHash(pkScript); hash != nil {
   333  		target[0] = cstPayToScriptHash
   334  		copy(target[1:21], hash)
   335  		return 21
   336  	}
   337  
   338  	// Pay-to-pubkey (compressed or uncompressed) script.
   339  	if valid, serializedPubKey := isPubKey(pkScript); valid {
   340  		pubKeyFormat := serializedPubKey[0]
   341  		switch pubKeyFormat {
   342  		case 0x02, 0x03:
   343  			if pubKeyFormat == 0x02 {
   344  				target[0] = cstPayToPubKeyCompEven
   345  			}
   346  			if pubKeyFormat == 0x03 {
   347  				target[0] = cstPayToPubKeyCompOdd
   348  			}
   349  			copy(target[1:33], serializedPubKey[1:33])
   350  			return 33
   351  		case 0x04:
   352  			// Encode the oddness of the serialized pubkey into the
   353  			// compressed script type.
   354  			target[0] = cstPayToPubKeyUncompEven
   355  			if (serializedPubKey[64] & 0x01) == 0x01 {
   356  				target[0] = cstPayToPubKeyUncompOdd
   357  			}
   358  			copy(target[1:33], serializedPubKey[1:33])
   359  			return 33
   360  		}
   361  	}
   362  
   363  	// When none of the above special cases apply, encode the unmodified
   364  	// script preceded by the script version, the sum of its size and
   365  	// the number of special cases encoded as a variable length quantity.
   366  	encodedSize := uint64(len(pkScript) + numSpecialScripts)
   367  	vlqSizeLen := putVLQ(target, encodedSize)
   368  	copy(target[vlqSizeLen:], pkScript)
   369  	return vlqSizeLen + len(pkScript)
   370  }
   371  
   372  // decompressScript returns the original script obtained by decompressing the
   373  // passed compressed script according to the domain specific compression
   374  // algorithm described above.
   375  //
   376  // NOTE: The script parameter must already have been proven to be long enough
   377  // to contain the number of bytes returned by decodeCompressedScriptSize or it
   378  // will panic.  This is acceptable since it is only an internal function.
   379  func decompressScript(compressedPkScript []byte,
   380  	compressionVersion uint32) []byte {
   381  	// Empty scripts, specified by 0x00, are considered nil.
   382  	if len(compressedPkScript) == 0 {
   383  		return nil
   384  	}
   385  
   386  	// Decode the script size and examine it for the special cases.
   387  	encodedScriptSize, bytesRead := deserializeVLQ(compressedPkScript)
   388  	switch encodedScriptSize {
   389  	// Pay-to-pubkey-hash script.  The resulting script is:
   390  	// <OP_DUP><OP_HASH160><20 byte hash><OP_EQUALVERIFY><OP_CHECKSIG>
   391  	case cstPayToPubKeyHash:
   392  		pkScript := make([]byte, 25)
   393  		pkScript[0] = txscript.OP_DUP
   394  		pkScript[1] = txscript.OP_HASH160
   395  		pkScript[2] = txscript.OP_DATA_20
   396  		copy(pkScript[3:], compressedPkScript[bytesRead:bytesRead+20])
   397  		pkScript[23] = txscript.OP_EQUALVERIFY
   398  		pkScript[24] = txscript.OP_CHECKSIG
   399  		return pkScript
   400  
   401  	// Pay-to-script-hash script.  The resulting script is:
   402  	// <OP_HASH160><20 byte script hash><OP_EQUAL>
   403  	case cstPayToScriptHash:
   404  		pkScript := make([]byte, 23)
   405  		pkScript[0] = txscript.OP_HASH160
   406  		pkScript[1] = txscript.OP_DATA_20
   407  		copy(pkScript[2:], compressedPkScript[bytesRead:bytesRead+20])
   408  		pkScript[22] = txscript.OP_EQUAL
   409  		return pkScript
   410  
   411  	// Pay-to-compressed-pubkey script.  The resulting script is:
   412  	// <OP_DATA_33><33 byte compressed pubkey><OP_CHECKSIG>
   413  	case cstPayToPubKeyCompEven, cstPayToPubKeyCompOdd:
   414  		pkScript := make([]byte, 35)
   415  		pkScript[0] = txscript.OP_DATA_33
   416  		oddness := byte(0x02)
   417  		if encodedScriptSize == cstPayToPubKeyCompOdd {
   418  			oddness = 0x03
   419  		}
   420  		pkScript[1] = oddness
   421  		copy(pkScript[2:], compressedPkScript[bytesRead:bytesRead+32])
   422  		pkScript[34] = txscript.OP_CHECKSIG
   423  		return pkScript
   424  
   425  	// Pay-to-uncompressed-pubkey script.  The resulting script is:
   426  	// <OP_DATA_65><65 byte uncompressed pubkey><OP_CHECKSIG>
   427  	case cstPayToPubKeyUncompEven, cstPayToPubKeyUncompOdd:
   428  		// Change the leading byte to the appropriate compressed pubkey
   429  		// identifier (0x02 or 0x03) so it can be decoded as a
   430  		// compressed pubkey.  This really should never fail since the
   431  		// encoding ensures it is valid before compressing to this type.
   432  		compressedKey := make([]byte, 33)
   433  		oddness := byte(0x02)
   434  		if encodedScriptSize == cstPayToPubKeyUncompOdd {
   435  			oddness = 0x03
   436  		}
   437  		compressedKey[0] = oddness
   438  		copy(compressedKey[1:], compressedPkScript[1:])
   439  		key, err := secp256k1.ParsePubKey(compressedKey)
   440  		if err != nil {
   441  			return nil
   442  		}
   443  
   444  		pkScript := make([]byte, 67)
   445  		pkScript[0] = txscript.OP_DATA_65
   446  		copy(pkScript[1:], key.SerializeUncompressed())
   447  		pkScript[66] = txscript.OP_CHECKSIG
   448  		return pkScript
   449  	}
   450  
   451  	// When none of the special cases apply, the script was encoded using
   452  	// the general format, so reduce the script size by the number of
   453  	// special cases and return the unmodified script.
   454  	scriptSize := int(encodedScriptSize - numSpecialScripts)
   455  	pkScript := make([]byte, scriptSize)
   456  	copy(pkScript, compressedPkScript[bytesRead:bytesRead+scriptSize])
   457  	return pkScript
   458  }
   459  
   460  // -----------------------------------------------------------------------------
   461  // In order to reduce the size of stored amounts, a domain specific compression
   462  // algorithm is used which relies on there typically being a lot of zeroes at
   463  // end of the amounts.  The compression algorithm used here was obtained from
   464  // Bitcoin Core, so all credits for the algorithm go to it.
   465  //
   466  // While this is simply exchanging one uint64 for another, the resulting value
   467  // for typical amounts has a much smaller magnitude which results in fewer bytes
   468  // when encoded as variable length quantity.  For example, consider the amount
   469  // of 0.1 DCR which is 10000000 atoms.  Encoding 10000000 as a VarInt would take
   470  // 4 bytes while encoding the compressed value of 8 as a VarInt only takes 1 byte.
   471  //
   472  // Essentially the compression is achieved by splitting the value into an
   473  // exponent in the range [0-9] and a digit in the range [1-9], when possible,
   474  // and encoding them in a way that can be decoded.  More specifically, the
   475  // encoding is as follows:
   476  // - 0 is 0
   477  // - Find the exponent, e, as the largest power of 10 that evenly divides the
   478  //   value up to a maximum of 9
   479  // - When e < 9, the final digit can't be 0 so store it as d and remove it by
   480  //   dividing the value by 10 (call the result n).  The encoded value is thus:
   481  //   1 + 10*(9*n + d-1) + e
   482  // - When e==9, the only thing known is the amount is not 0.  The encoded value
   483  //   is thus:
   484  //   1 + 10*(n-1) + e   ==   10 + 10*(n-1)
   485  //
   486  // Example encodings:
   487  // (The numbers in parenthesis are the number of bytes when serialized as a VarInt)
   488  //            0 (1) -> 0        (1)           *  0.00000000 BTC
   489  //         1000 (2) -> 4        (1)           *  0.00001000 BTC
   490  //        10000 (2) -> 5        (1)           *  0.00010000 BTC
   491  //     12345678 (4) -> 111111101(4)           *  0.12345678 BTC
   492  //     50000000 (4) -> 47       (1)           *  0.50000000 BTC
   493  //    100000000 (4) -> 9        (1)           *  1.00000000 BTC
   494  //    500000000 (5) -> 49       (1)           *  5.00000000 BTC
   495  //   1000000000 (5) -> 10       (1)           * 10.00000000 BTC
   496  // -----------------------------------------------------------------------------
   497  
   498  // compressTxOutAmount compresses the passed amount according to the domain
   499  // specific compression algorithm described above.
   500  func compressTxOutAmount(amount uint64) uint64 {
   501  	// No need to do any work if it's zero.
   502  	if amount == 0 {
   503  		return 0
   504  	}
   505  
   506  	// Find the largest power of 10 (max of 9) that evenly divides the
   507  	// value.
   508  	exponent := uint64(0)
   509  	for amount%10 == 0 && exponent < 9 {
   510  		amount /= 10
   511  		exponent++
   512  	}
   513  
   514  	// The compressed result for exponents less than 9 is:
   515  	// 1 + 10*(9*n + d-1) + e
   516  	if exponent < 9 {
   517  		lastDigit := amount % 10
   518  		amount /= 10
   519  		return 1 + 10*(9*amount+lastDigit-1) + exponent
   520  	}
   521  
   522  	// The compressed result for an exponent of 9 is:
   523  	// 1 + 10*(n-1) + e   ==   10 + 10*(n-1)
   524  	return 10 + 10*(amount-1)
   525  }
   526  
   527  // decompressTxOutAmount returns the original amount the passed compressed
   528  // amount represents according to the domain specific compression algorithm
   529  // described above.
   530  func decompressTxOutAmount(amount uint64) uint64 {
   531  	// No need to do any work if it's zero.
   532  	if amount == 0 {
   533  		return 0
   534  	}
   535  
   536  	// The decompressed amount is either of the following two equations:
   537  	// x = 1 + 10*(9*n + d - 1) + e
   538  	// x = 1 + 10*(n - 1)       + 9
   539  	amount--
   540  
   541  	// The decompressed amount is now one of the following two equations:
   542  	// x = 10*(9*n + d - 1) + e
   543  	// x = 10*(n - 1)       + 9
   544  	exponent := amount % 10
   545  	amount /= 10
   546  
   547  	// The decompressed amount is now one of the following two equations:
   548  	// x = 9*n + d - 1  | where e < 9
   549  	// x = n - 1        | where e = 9
   550  	var n uint64
   551  	if exponent < 9 {
   552  		lastDigit := amount%9 + 1
   553  		amount /= 9
   554  		n = amount*10 + lastDigit
   555  	} else {
   556  		n = amount + 1
   557  	}
   558  
   559  	// Apply the exponent.
   560  	for ; exponent > 0; exponent-- {
   561  		n *= 10
   562  	}
   563  
   564  	return n
   565  }
   566  
   567  // -----------------------------------------------------------------------------
   568  // Compressed transaction outputs for UTXOS consist of an amount and a public
   569  // key script both compressed using the domain specific compression algorithms
   570  // previously described.
   571  //
   572  // The serialized format is:
   573  //
   574  //   <compressed amount><compressed script>
   575  //
   576  //   Field                 Type     Size
   577  //     compressed amount   VLQ      variable
   578  //     compressed script   []byte   variable
   579  // -----------------------------------------------------------------------------
   580  
   581  // compressedTxOutSize returns the number of bytes the passed transaction output
   582  // fields would take when encoded with the format described above.  The
   583  // preCompressed flag indicates the provided amount and script are already
   584  // compressed.  This is useful since loaded utxo entries are not decompressed
   585  // until the output is accessed.
   586  func compressedTxOutSize(amount uint64, scriptVersion uint16, pkScript []byte,
   587  	compressionVersion uint32, preCompressed bool, hasAmount bool) int {
   588  	scriptVersionSize := serializeSizeVLQ(uint64(scriptVersion))
   589  	if preCompressed && !hasAmount {
   590  		return scriptVersionSize + len(pkScript)
   591  	}
   592  	if preCompressed && hasAmount {
   593  		return scriptVersionSize + serializeSizeVLQ(compressTxOutAmount(amount)) +
   594  			len(pkScript)
   595  	}
   596  	if !preCompressed && !hasAmount {
   597  		return scriptVersionSize + compressedScriptSize(scriptVersion,
   598  			pkScript, compressionVersion)
   599  	}
   600  
   601  	// if !preCompressed && hasAmount
   602  	return scriptVersionSize + serializeSizeVLQ(compressTxOutAmount(amount)) +
   603  		compressedScriptSize(scriptVersion, pkScript, compressionVersion)
   604  }
   605  
   606  // putCompressedTxOut potentially compresses the passed amount and script
   607  // according to their domain specific compression algorithms and encodes them
   608  // directly into the passed target byte slice with the format described above.
   609  // The preCompressed flag indicates the provided amount and script are already
   610  // compressed in which case the values are not modified.  This is useful since
   611  // loaded utxo entries are not decompressed until the output is accessed.  The
   612  // target byte slice must be at least large enough to handle the number of bytes
   613  // returned by the compressedTxOutSize function or it will panic.
   614  func putCompressedTxOut(target []byte, amount uint64, scriptVersion uint16,
   615  	pkScript []byte, compressionVersion uint32, preCompressed bool,
   616  	hasAmount bool) int {
   617  	if preCompressed && hasAmount {
   618  		offset := putVLQ(target, compressTxOutAmount(amount))
   619  		offset += putVLQ(target[offset:], uint64(scriptVersion))
   620  		copy(target[offset:], pkScript)
   621  		return offset + len(pkScript)
   622  	}
   623  	if preCompressed && !hasAmount {
   624  		offset := putVLQ(target, uint64(scriptVersion))
   625  		copy(target[offset:], pkScript)
   626  		return offset + len(pkScript)
   627  	}
   628  	if !preCompressed && !hasAmount {
   629  		offset := putVLQ(target, uint64(scriptVersion))
   630  		offset += putCompressedScript(target[offset:], scriptVersion, pkScript,
   631  			compressionVersion)
   632  		return offset
   633  	}
   634  
   635  	// if !preCompressed && hasAmount
   636  	offset := putVLQ(target, compressTxOutAmount(amount))
   637  	offset += putVLQ(target[offset:], uint64(scriptVersion))
   638  	offset += putCompressedScript(target[offset:], scriptVersion, pkScript,
   639  		compressionVersion)
   640  	return offset
   641  }
   642  
   643  // decodeCompressedTxOut decodes the passed compressed txout, possibly followed
   644  // by other data, into its compressed amount and compressed script and returns
   645  // them along with the number of bytes they occupied.
   646  func decodeCompressedTxOut(serialized []byte, compressionVersion uint32,
   647  	hasAmount bool) (int64, uint16, []byte, int, error) {
   648  	var amount int64
   649  	var bytesRead int
   650  	var offset int
   651  	if hasAmount {
   652  		// Deserialize the compressed amount and ensure there are bytes
   653  		// remaining for the compressed script.
   654  		var compressedAmount uint64
   655  		compressedAmount, bytesRead = deserializeVLQ(serialized)
   656  		if bytesRead >= len(serialized) {
   657  			return 0, 0, nil, bytesRead, errDeserialize("unexpected end of " +
   658  				"data after compressed amount")
   659  		}
   660  		amount = int64(decompressTxOutAmount(compressedAmount))
   661  		offset += bytesRead
   662  	}
   663  
   664  	// Decode the script version.
   665  	var scriptVersion uint64
   666  	scriptVersion, bytesRead = deserializeVLQ(serialized[offset:])
   667  	offset += bytesRead
   668  
   669  	// Decode the compressed script size and ensure there are enough bytes
   670  	// left in the slice for it.
   671  	scriptSize := decodeCompressedScriptSize(serialized[offset:],
   672  		compressionVersion)
   673  	if scriptSize < 0 {
   674  		return 0, 0, nil, offset, errDeserialize("negative script size")
   675  	}
   676  	if len(serialized[offset:]) < scriptSize {
   677  		return 0, 0, nil, offset, errDeserialize(fmt.Sprintf("unexpected end of "+
   678  			"data after script size (got %v, need %v)", len(serialized[offset:]),
   679  			scriptSize))
   680  	}
   681  
   682  	// Make a copy of the compressed script so the original serialized data
   683  	// can be released as soon as possible.
   684  	compressedScript := make([]byte, scriptSize)
   685  	copy(compressedScript, serialized[offset:offset+scriptSize])
   686  
   687  	return amount, uint16(scriptVersion), compressedScript,
   688  		offset + scriptSize, nil
   689  }
   690  
   691  // -----------------------------------------------------------------------------
   692  // Decred specific transaction encoding flags
   693  //
   694  // Details about a transaction needed to determine how it may be spent
   695  // according to consensus rules are given by these flags.
   696  //
   697  // The following details are encoded into a single byte, where the index
   698  // of the bit is given in zeroeth order:
   699  //     0: Is coinbase
   700  //     1: Has an expiry
   701  //   2-3: Transaction type
   702  //     4: Fully spent
   703  //   5-7: Unused
   704  //
   705  // 0, 1, and 4 are bit flags, while the transaction type is encoded with a bitmask
   706  // and used to describe the underlying int.
   707  //
   708  // The fully spent flag should always come as the *last* flag (highest bit index)
   709  // in this data type should flags be updated to include more rules in the future,
   710  // such as rules governing new script OP codes. This ensures that we may still use
   711  // these flags in the UTX serialized data without consequence, where the last flag
   712  // indicating fully spent will always be zeroed.
   713  //
   714  // -----------------------------------------------------------------------------
   715  
   716  const (
   717  	// txTypeBitmask describes the bitmask that yields the 3rd and 4th bits
   718  	// from the flags byte.
   719  	txTypeBitmask = 0x0c
   720  
   721  	// txTypeShift is the number of bits to shift falgs to the right to yield the
   722  	// correct integer value after applying the bitmask with AND.
   723  	txTypeShift = 2
   724  )
   725  
   726  // encodeFlags encodes transaction flags into a single byte.
   727  func encodeFlags(isCoinBase bool, hasExpiry bool, txType stake.TxType, fullySpent bool) byte {
   728  	b := uint8(txType)
   729  	b <<= txTypeShift
   730  
   731  	if isCoinBase {
   732  		b |= 0x01 // Set bit 0
   733  	}
   734  	if hasExpiry {
   735  		b |= 0x02 // Set bit 1
   736  	}
   737  	if fullySpent {
   738  		b |= 0x10 // Set bit 4
   739  	}
   740  
   741  	return b
   742  }
   743  
   744  // decodeFlags decodes transaction flags from a single byte into their respective
   745  // data types.
   746  func decodeFlags(b byte) (bool, bool, stake.TxType, bool) {
   747  	isCoinBase := b&0x01 != 0
   748  	hasExpiry := b&(1<<1) != 0
   749  	fullySpent := b&(1<<4) != 0
   750  	txType := stake.TxType((b & txTypeBitmask) >> txTypeShift)
   751  
   752  	return isCoinBase, hasExpiry, txType, fullySpent
   753  }
   754  
   755  // decodeFlagsFullySpent decodes whether or not a transaction was fully spent.
   756  func decodeFlagsFullySpent(b byte) bool {
   757  	return b&(1<<4) != 0
   758  }