pkscript.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. package txscript
  2. import (
  3. sha256 "github.com/minio/sha256-simd"
  4. "github.com/pkt-cash/pktd/btcutil/er"
  5. "github.com/pkt-cash/pktd/txscript/parsescript"
  6. "github.com/pkt-cash/pktd/btcec"
  7. "github.com/pkt-cash/pktd/btcutil"
  8. "github.com/pkt-cash/pktd/chaincfg"
  9. "github.com/pkt-cash/pktd/wire"
  10. )
  11. const (
  12. // minPubKeyHashSigScriptLen is the minimum length of a signature script
  13. // that spends a P2PKH output. The length is composed of the following:
  14. // Signature length (1 byte)
  15. // Signature (min 8 bytes)
  16. // Signature hash type (1 byte)
  17. // Public key length (1 byte)
  18. // Public key (33 byte)
  19. minPubKeyHashSigScriptLen = 1 + btcec.MinSigLen + 1 + 1 + 33
  20. // maxPubKeyHashSigScriptLen is the maximum length of a signature script
  21. // that spends a P2PKH output. The length is composed of the following:
  22. // Signature length (1 byte)
  23. // Signature (max 72 bytes)
  24. // Signature hash type (1 byte)
  25. // Public key length (1 byte)
  26. // Public key (33 byte)
  27. maxPubKeyHashSigScriptLen = 1 + 72 + 1 + 1 + 33
  28. // compressedPubKeyLen is the length in bytes of a compressed public
  29. // key.
  30. compressedPubKeyLen = 33
  31. // pubKeyHashLen is the length of a P2PKH script.
  32. pubKeyHashLen = 25
  33. // witnessV0PubKeyHashLen is the length of a P2WPKH script.
  34. witnessV0PubKeyHashLen = 22
  35. // scriptHashLen is the length of a P2SH script.
  36. scriptHashLen = 23
  37. // witnessV0ScriptHashLen is the length of a P2WSH script.
  38. witnessV0ScriptHashLen = 34
  39. // maxLen is the maximum script length supported by ParsePkScript.
  40. maxLen = witnessV0ScriptHashLen
  41. )
  42. // ErrUnsupportedScriptType is an error returned when we attempt to
  43. // parse/re-compute an output script into a PkScript struct.
  44. var ErrUnsupportedScriptType = er.GenericErrorType.CodeWithDetail("ErrUnsupportedScriptType",
  45. "unsupported script type")
  46. // PkScript is a wrapper struct around a byte array, allowing it to be used
  47. // as a map index.
  48. type PkScript struct {
  49. // class is the type of the script encoded within the byte array. This
  50. // is used to determine the correct length of the script within the byte
  51. // array.
  52. class ScriptClass
  53. // script is the script contained within a byte array. If the script is
  54. // smaller than the length of the byte array, it will be padded with 0s
  55. // at the end.
  56. script [maxLen]byte
  57. }
  58. // ParsePkScript parses an output script into the PkScript struct.
  59. // ErrUnsupportedScriptType is returned when attempting to parse an unsupported
  60. // script type.
  61. func ParsePkScript(pkScript []byte) (PkScript, er.R) {
  62. var outputScript PkScript
  63. scriptClass, _, _, err := ExtractPkScriptAddrs(
  64. pkScript, &chaincfg.MainNetParams,
  65. )
  66. if err != nil {
  67. return outputScript, er.Errorf("unable to parse script type: "+
  68. "%v", err)
  69. }
  70. if !isSupportedScriptType(scriptClass) {
  71. return outputScript, ErrUnsupportedScriptType.Default()
  72. }
  73. outputScript.class = scriptClass
  74. copy(outputScript.script[:], pkScript)
  75. return outputScript, nil
  76. }
  77. // isSupportedScriptType determines whether the script type is supported by the
  78. // PkScript struct.
  79. func isSupportedScriptType(class ScriptClass) bool {
  80. switch class {
  81. case PubKeyHashTy, WitnessV0PubKeyHashTy, ScriptHashTy,
  82. WitnessV0ScriptHashTy:
  83. return true
  84. default:
  85. return false
  86. }
  87. }
  88. // Class returns the script type.
  89. func (s PkScript) Class() ScriptClass {
  90. return s.class
  91. }
  92. // Script returns the script as a byte slice without any padding.
  93. func (s PkScript) Script() []byte {
  94. var script []byte
  95. switch s.class {
  96. case PubKeyHashTy:
  97. script = make([]byte, pubKeyHashLen)
  98. copy(script, s.script[:pubKeyHashLen])
  99. case WitnessV0PubKeyHashTy:
  100. script = make([]byte, witnessV0PubKeyHashLen)
  101. copy(script, s.script[:witnessV0PubKeyHashLen])
  102. case ScriptHashTy:
  103. script = make([]byte, scriptHashLen)
  104. copy(script, s.script[:scriptHashLen])
  105. case WitnessV0ScriptHashTy:
  106. script = make([]byte, witnessV0ScriptHashLen)
  107. copy(script, s.script[:witnessV0ScriptHashLen])
  108. default:
  109. // Unsupported script type.
  110. return nil
  111. }
  112. return script
  113. }
  114. // Address encodes the script into an address for the given chain.
  115. func (s PkScript) Address(chainParams *chaincfg.Params) (btcutil.Address, er.R) {
  116. _, addrs, _, err := ExtractPkScriptAddrs(s.Script(), chainParams)
  117. if err != nil {
  118. return nil, er.Errorf("unable to parse address: %v", err)
  119. }
  120. return addrs[0], nil
  121. }
  122. // String returns a hex-encoded string representation of the script.
  123. func (s PkScript) String() string {
  124. str, _ := DisasmString(s.Script())
  125. return str
  126. }
  127. // ComputePkScript computes the script of an output by looking at the spending
  128. // input's signature script or witness.
  129. //
  130. // NOTE: Only P2PKH, P2SH, P2WSH, and P2WPKH redeem scripts are supported.
  131. func ComputePkScript(sigScript []byte, witness wire.TxWitness) (PkScript, er.R) {
  132. switch {
  133. case len(sigScript) > 0:
  134. return computeNonWitnessPkScript(sigScript)
  135. case len(witness) > 0:
  136. return computeWitnessPkScript(witness)
  137. default:
  138. return PkScript{}, ErrUnsupportedScriptType.Default()
  139. }
  140. }
  141. // computeNonWitnessPkScript computes the script of an output by looking at the
  142. // spending input's signature script.
  143. func computeNonWitnessPkScript(sigScript []byte) (PkScript, er.R) {
  144. switch {
  145. // Since we only support P2PKH and P2SH scripts as the only non-witness
  146. // script types, we should expect to see a push only script.
  147. case !IsPushOnlyScript(sigScript):
  148. return PkScript{}, ErrUnsupportedScriptType.Default()
  149. // If a signature script is provided with a length long enough to
  150. // represent a P2PKH script, then we'll attempt to parse the compressed
  151. // public key from it.
  152. case len(sigScript) >= minPubKeyHashSigScriptLen &&
  153. len(sigScript) <= maxPubKeyHashSigScriptLen:
  154. // The public key should be found as the last part of the
  155. // signature script. We'll attempt to parse it to ensure this is
  156. // a P2PKH redeem script.
  157. pubKey := sigScript[len(sigScript)-compressedPubKeyLen:]
  158. if btcec.IsCompressedPubKey(pubKey) {
  159. pubKeyHash := btcutil.Hash160(pubKey)
  160. script, err := payToPubKeyHashScript(pubKeyHash)
  161. if err != nil {
  162. return PkScript{}, err
  163. }
  164. pkScript := PkScript{class: PubKeyHashTy}
  165. copy(pkScript.script[:], script)
  166. return pkScript, nil
  167. }
  168. fallthrough
  169. // If we failed to parse a compressed public key from the script in the
  170. // case above, or if the script length is not that of a P2PKH one, we
  171. // can assume it's a P2SH signature script.
  172. default:
  173. // The redeem script will always be the last data push of the
  174. // signature script, so we'll parse the script into opcodes to
  175. // obtain it.
  176. parsedOpcodes, err := parsescript.ParseScript(sigScript)
  177. if err != nil {
  178. return PkScript{}, err
  179. }
  180. redeemScript := parsedOpcodes[len(parsedOpcodes)-1].Data
  181. scriptHash := btcutil.Hash160(redeemScript)
  182. script, err := payToScriptHashScript(scriptHash)
  183. if err != nil {
  184. return PkScript{}, err
  185. }
  186. pkScript := PkScript{class: ScriptHashTy}
  187. copy(pkScript.script[:], script)
  188. return pkScript, nil
  189. }
  190. }
  191. // computeWitnessPkScript computes the script of an output by looking at the
  192. // spending input's witness.
  193. func computeWitnessPkScript(witness wire.TxWitness) (PkScript, er.R) {
  194. // We'll use the last item of the witness stack to determine the proper
  195. // witness type.
  196. lastWitnessItem := witness[len(witness)-1]
  197. var pkScript PkScript
  198. switch {
  199. // If the witness stack has a size of 2 and its last item is a
  200. // compressed public key, then this is a P2WPKH witness.
  201. case len(witness) == 2 && len(lastWitnessItem) == compressedPubKeyLen:
  202. pubKeyHash := btcutil.Hash160(lastWitnessItem)
  203. script, err := payToWitnessPubKeyHashScript(pubKeyHash)
  204. if err != nil {
  205. return pkScript, err
  206. }
  207. pkScript.class = WitnessV0PubKeyHashTy
  208. copy(pkScript.script[:], script)
  209. // For any other witnesses, we'll assume it's a P2WSH witness.
  210. default:
  211. scriptHash := sha256.Sum256(lastWitnessItem)
  212. script, err := payToWitnessScriptHashScript(scriptHash[:])
  213. if err != nil {
  214. return pkScript, err
  215. }
  216. pkScript.class = WitnessV0ScriptHashTy
  217. copy(pkScript.script[:], script)
  218. }
  219. return pkScript, nil
  220. }