mirror of
https://github.com/muun/recovery.git
synced 2025-11-11 06:20:16 -05:00
Release v0.1.0
This commit is contained in:
63
vendor/github.com/btcsuite/btcd/txscript/README.md
generated
vendored
Normal file
63
vendor/github.com/btcsuite/btcd/txscript/README.md
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
txscript
|
||||
========
|
||||
|
||||
[](https://travis-ci.org/btcsuite/btcd)
|
||||
[](http://copyfree.org)
|
||||
[](http://godoc.org/github.com/btcsuite/btcd/txscript)
|
||||
|
||||
Package txscript implements the bitcoin transaction script language. There is
|
||||
a comprehensive test suite.
|
||||
|
||||
This package has intentionally been designed so it can be used as a standalone
|
||||
package for any projects needing to use or validate bitcoin transaction scripts.
|
||||
|
||||
## Bitcoin Scripts
|
||||
|
||||
Bitcoin provides a stack-based, FORTH-like language for the scripts in
|
||||
the bitcoin transactions. This language is not turing complete
|
||||
although it is still fairly powerful. A description of the language
|
||||
can be found at https://en.bitcoin.it/wiki/Script
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/txscript
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Standard Pay-to-pubkey-hash Script](http://godoc.org/github.com/btcsuite/btcd/txscript#example-PayToAddrScript)
|
||||
Demonstrates creating a script which pays to a bitcoin address. It also
|
||||
prints the created script hex and uses the DisasmString function to display
|
||||
the disassembled script.
|
||||
|
||||
* [Extracting Details from Standard Scripts](http://godoc.org/github.com/btcsuite/btcd/txscript#example-ExtractPkScriptAddrs)
|
||||
Demonstrates extracting information from a standard public key script.
|
||||
|
||||
* [Manually Signing a Transaction Output](http://godoc.org/github.com/btcsuite/btcd/txscript#example-SignTxOutput)
|
||||
Demonstrates manually creating and signing a redeem transaction.
|
||||
|
||||
## GPG Verification Key
|
||||
|
||||
All official release tags are signed by Conformal so users can ensure the code
|
||||
has not been tampered with and is coming from the btcsuite developers. To
|
||||
verify the signature perform the following:
|
||||
|
||||
- Download the public key from the Conformal website at
|
||||
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
|
||||
|
||||
- Import the public key into your GPG keyring:
|
||||
```bash
|
||||
gpg --import GIT-GPG-KEY-conformal.txt
|
||||
```
|
||||
|
||||
- Verify the release tag with the following command where `TAG_NAME` is a
|
||||
placeholder for the specific tag:
|
||||
```bash
|
||||
git tag -v TAG_NAME
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Package txscript is licensed under the [copyfree](http://copyfree.org) ISC
|
||||
License.
|
||||
13
vendor/github.com/btcsuite/btcd/txscript/consensus.go
generated
vendored
Normal file
13
vendor/github.com/btcsuite/btcd/txscript/consensus.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2015-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
const (
|
||||
// LockTimeThreshold is the number below which a lock time is
|
||||
// interpreted to be a block number. Since an average of one block
|
||||
// is generated per 10 minutes, this allows blocks for about 9,512
|
||||
// years.
|
||||
LockTimeThreshold = 5e8 // Tue Nov 5 00:53:20 1985 UTC
|
||||
)
|
||||
42
vendor/github.com/btcsuite/btcd/txscript/doc.go
generated
vendored
Normal file
42
vendor/github.com/btcsuite/btcd/txscript/doc.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package txscript implements the bitcoin transaction script language.
|
||||
|
||||
A complete description of the script language used by bitcoin can be found at
|
||||
https://en.bitcoin.it/wiki/Script. The following only serves as a quick
|
||||
overview to provide information on how to use the package.
|
||||
|
||||
This package provides data structures and functions to parse and execute
|
||||
bitcoin transaction scripts.
|
||||
|
||||
Script Overview
|
||||
|
||||
Bitcoin transaction scripts are written in a stack-base, FORTH-like language.
|
||||
|
||||
The bitcoin script language consists of a number of opcodes which fall into
|
||||
several categories such pushing and popping data to and from the stack,
|
||||
performing basic and bitwise arithmetic, conditional branching, comparing
|
||||
hashes, and checking cryptographic signatures. Scripts are processed from left
|
||||
to right and intentionally do not provide loops.
|
||||
|
||||
The vast majority of Bitcoin scripts at the time of this writing are of several
|
||||
standard forms which consist of a spender providing a public key and a signature
|
||||
which proves the spender owns the associated private key. This information
|
||||
is used to prove the the spender is authorized to perform the transaction.
|
||||
|
||||
One benefit of using a scripting language is added flexibility in specifying
|
||||
what conditions must be met in order to spend bitcoins.
|
||||
|
||||
Errors
|
||||
|
||||
Errors returned by this package are of type txscript.Error. This allows the
|
||||
caller to programmatically determine the specific error by examining the
|
||||
ErrorCode field of the type asserted txscript.Error while still providing rich
|
||||
error messages with contextual information. A convenience function named
|
||||
IsErrorCode is also provided to allow callers to easily check for a specific
|
||||
error code. See ErrorCode in the package documentation for a full list.
|
||||
*/
|
||||
package txscript
|
||||
1004
vendor/github.com/btcsuite/btcd/txscript/engine.go
generated
vendored
Normal file
1004
vendor/github.com/btcsuite/btcd/txscript/engine.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
453
vendor/github.com/btcsuite/btcd/txscript/error.go
generated
vendored
Normal file
453
vendor/github.com/btcsuite/btcd/txscript/error.go
generated
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ErrorCode identifies a kind of script error.
|
||||
type ErrorCode int
|
||||
|
||||
// These constants are used to identify a specific Error.
|
||||
const (
|
||||
// ErrInternal is returned if internal consistency checks fail. In
|
||||
// practice this error should never be seen as it would mean there is an
|
||||
// error in the engine logic.
|
||||
ErrInternal ErrorCode = iota
|
||||
|
||||
// ---------------------------------------
|
||||
// Failures related to improper API usage.
|
||||
// ---------------------------------------
|
||||
|
||||
// ErrInvalidFlags is returned when the passed flags to NewEngine
|
||||
// contain an invalid combination.
|
||||
ErrInvalidFlags
|
||||
|
||||
// ErrInvalidIndex is returned when an out-of-bounds index is passed to
|
||||
// a function.
|
||||
ErrInvalidIndex
|
||||
|
||||
// ErrUnsupportedAddress is returned when a concrete type that
|
||||
// implements a btcutil.Address is not a supported type.
|
||||
ErrUnsupportedAddress
|
||||
|
||||
// ErrNotMultisigScript is returned from CalcMultiSigStats when the
|
||||
// provided script is not a multisig script.
|
||||
ErrNotMultisigScript
|
||||
|
||||
// ErrTooManyRequiredSigs is returned from MultiSigScript when the
|
||||
// specified number of required signatures is larger than the number of
|
||||
// provided public keys.
|
||||
ErrTooManyRequiredSigs
|
||||
|
||||
// ErrTooMuchNullData is returned from NullDataScript when the length of
|
||||
// the provided data exceeds MaxDataCarrierSize.
|
||||
ErrTooMuchNullData
|
||||
|
||||
// ------------------------------------------
|
||||
// Failures related to final execution state.
|
||||
// ------------------------------------------
|
||||
|
||||
// ErrEarlyReturn is returned when OP_RETURN is executed in the script.
|
||||
ErrEarlyReturn
|
||||
|
||||
// ErrEmptyStack is returned when the script evaluated without error,
|
||||
// but terminated with an empty top stack element.
|
||||
ErrEmptyStack
|
||||
|
||||
// ErrEvalFalse is returned when the script evaluated without error but
|
||||
// terminated with a false top stack element.
|
||||
ErrEvalFalse
|
||||
|
||||
// ErrScriptUnfinished is returned when CheckErrorCondition is called on
|
||||
// a script that has not finished executing.
|
||||
ErrScriptUnfinished
|
||||
|
||||
// ErrScriptDone is returned when an attempt to execute an opcode is
|
||||
// made once all of them have already been executed. This can happen
|
||||
// due to things such as a second call to Execute or calling Step after
|
||||
// all opcodes have already been executed.
|
||||
ErrInvalidProgramCounter
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Failures related to exceeding maximum allowed limits.
|
||||
// -----------------------------------------------------
|
||||
|
||||
// ErrScriptTooBig is returned if a script is larger than MaxScriptSize.
|
||||
ErrScriptTooBig
|
||||
|
||||
// ErrElementTooBig is returned if the size of an element to be pushed
|
||||
// to the stack is over MaxScriptElementSize.
|
||||
ErrElementTooBig
|
||||
|
||||
// ErrTooManyOperations is returned if a script has more than
|
||||
// MaxOpsPerScript opcodes that do not push data.
|
||||
ErrTooManyOperations
|
||||
|
||||
// ErrStackOverflow is returned when stack and altstack combined depth
|
||||
// is over the limit.
|
||||
ErrStackOverflow
|
||||
|
||||
// ErrInvalidPubKeyCount is returned when the number of public keys
|
||||
// specified for a multsig is either negative or greater than
|
||||
// MaxPubKeysPerMultiSig.
|
||||
ErrInvalidPubKeyCount
|
||||
|
||||
// ErrInvalidSignatureCount is returned when the number of signatures
|
||||
// specified for a multisig is either negative or greater than the
|
||||
// number of public keys.
|
||||
ErrInvalidSignatureCount
|
||||
|
||||
// ErrNumberTooBig is returned when the argument for an opcode that
|
||||
// expects numeric input is larger than the expected maximum number of
|
||||
// bytes. For the most part, opcodes that deal with stack manipulation
|
||||
// via offsets, arithmetic, numeric comparison, and boolean logic are
|
||||
// those that this applies to. However, any opcode that expects numeric
|
||||
// input may fail with this code.
|
||||
ErrNumberTooBig
|
||||
|
||||
// --------------------------------------------
|
||||
// Failures related to verification operations.
|
||||
// --------------------------------------------
|
||||
|
||||
// ErrVerify is returned when OP_VERIFY is encountered in a script and
|
||||
// the top item on the data stack does not evaluate to true.
|
||||
ErrVerify
|
||||
|
||||
// ErrEqualVerify is returned when OP_EQUALVERIFY is encountered in a
|
||||
// script and the top item on the data stack does not evaluate to true.
|
||||
ErrEqualVerify
|
||||
|
||||
// ErrNumEqualVerify is returned when OP_NUMEQUALVERIFY is encountered
|
||||
// in a script and the top item on the data stack does not evaluate to
|
||||
// true.
|
||||
ErrNumEqualVerify
|
||||
|
||||
// ErrCheckSigVerify is returned when OP_CHECKSIGVERIFY is encountered
|
||||
// in a script and the top item on the data stack does not evaluate to
|
||||
// true.
|
||||
ErrCheckSigVerify
|
||||
|
||||
// ErrCheckSigVerify is returned when OP_CHECKMULTISIGVERIFY is
|
||||
// encountered in a script and the top item on the data stack does not
|
||||
// evaluate to true.
|
||||
ErrCheckMultiSigVerify
|
||||
|
||||
// --------------------------------------------
|
||||
// Failures related to improper use of opcodes.
|
||||
// --------------------------------------------
|
||||
|
||||
// ErrDisabledOpcode is returned when a disabled opcode is encountered
|
||||
// in a script.
|
||||
ErrDisabledOpcode
|
||||
|
||||
// ErrReservedOpcode is returned when an opcode marked as reserved
|
||||
// is encountered in a script.
|
||||
ErrReservedOpcode
|
||||
|
||||
// ErrMalformedPush is returned when a data push opcode tries to push
|
||||
// more bytes than are left in the script.
|
||||
ErrMalformedPush
|
||||
|
||||
// ErrInvalidStackOperation is returned when a stack operation is
|
||||
// attempted with a number that is invalid for the current stack size.
|
||||
ErrInvalidStackOperation
|
||||
|
||||
// ErrUnbalancedConditional is returned when an OP_ELSE or OP_ENDIF is
|
||||
// encountered in a script without first having an OP_IF or OP_NOTIF or
|
||||
// the end of script is reached without encountering an OP_ENDIF when
|
||||
// an OP_IF or OP_NOTIF was previously encountered.
|
||||
ErrUnbalancedConditional
|
||||
|
||||
// ---------------------------------
|
||||
// Failures related to malleability.
|
||||
// ---------------------------------
|
||||
|
||||
// ErrMinimalData is returned when the ScriptVerifyMinimalData flag
|
||||
// is set and the script contains push operations that do not use
|
||||
// the minimal opcode required.
|
||||
ErrMinimalData
|
||||
|
||||
// ErrInvalidSigHashType is returned when a signature hash type is not
|
||||
// one of the supported types.
|
||||
ErrInvalidSigHashType
|
||||
|
||||
// ErrSigTooShort is returned when a signature that should be a
|
||||
// canonically-encoded DER signature is too short.
|
||||
ErrSigTooShort
|
||||
|
||||
// ErrSigTooLong is returned when a signature that should be a
|
||||
// canonically-encoded DER signature is too long.
|
||||
ErrSigTooLong
|
||||
|
||||
// ErrSigInvalidSeqID is returned when a signature that should be a
|
||||
// canonically-encoded DER signature does not have the expected ASN.1
|
||||
// sequence ID.
|
||||
ErrSigInvalidSeqID
|
||||
|
||||
// ErrSigInvalidDataLen is returned a signature that should be a
|
||||
// canonically-encoded DER signature does not specify the correct number
|
||||
// of remaining bytes for the R and S portions.
|
||||
ErrSigInvalidDataLen
|
||||
|
||||
// ErrSigMissingSTypeID is returned a signature that should be a
|
||||
// canonically-encoded DER signature does not provide the ASN.1 type ID
|
||||
// for S.
|
||||
ErrSigMissingSTypeID
|
||||
|
||||
// ErrSigMissingSLen is returned when a signature that should be a
|
||||
// canonically-encoded DER signature does not provide the length of S.
|
||||
ErrSigMissingSLen
|
||||
|
||||
// ErrSigInvalidSLen is returned a signature that should be a
|
||||
// canonically-encoded DER signature does not specify the correct number
|
||||
// of bytes for the S portion.
|
||||
ErrSigInvalidSLen
|
||||
|
||||
// ErrSigInvalidRIntID is returned when a signature that should be a
|
||||
// canonically-encoded DER signature does not have the expected ASN.1
|
||||
// integer ID for R.
|
||||
ErrSigInvalidRIntID
|
||||
|
||||
// ErrSigZeroRLen is returned when a signature that should be a
|
||||
// canonically-encoded DER signature has an R length of zero.
|
||||
ErrSigZeroRLen
|
||||
|
||||
// ErrSigNegativeR is returned when a signature that should be a
|
||||
// canonically-encoded DER signature has a negative value for R.
|
||||
ErrSigNegativeR
|
||||
|
||||
// ErrSigTooMuchRPadding is returned when a signature that should be a
|
||||
// canonically-encoded DER signature has too much padding for R.
|
||||
ErrSigTooMuchRPadding
|
||||
|
||||
// ErrSigInvalidSIntID is returned when a signature that should be a
|
||||
// canonically-encoded DER signature does not have the expected ASN.1
|
||||
// integer ID for S.
|
||||
ErrSigInvalidSIntID
|
||||
|
||||
// ErrSigZeroSLen is returned when a signature that should be a
|
||||
// canonically-encoded DER signature has an S length of zero.
|
||||
ErrSigZeroSLen
|
||||
|
||||
// ErrSigNegativeS is returned when a signature that should be a
|
||||
// canonically-encoded DER signature has a negative value for S.
|
||||
ErrSigNegativeS
|
||||
|
||||
// ErrSigTooMuchSPadding is returned when a signature that should be a
|
||||
// canonically-encoded DER signature has too much padding for S.
|
||||
ErrSigTooMuchSPadding
|
||||
|
||||
// ErrSigHighS is returned when the ScriptVerifyLowS flag is set and the
|
||||
// script contains any signatures whose S values are higher than the
|
||||
// half order.
|
||||
ErrSigHighS
|
||||
|
||||
// ErrNotPushOnly is returned when a script that is required to only
|
||||
// push data to the stack performs other operations. A couple of cases
|
||||
// where this applies is for a pay-to-script-hash signature script when
|
||||
// bip16 is active and when the ScriptVerifySigPushOnly flag is set.
|
||||
ErrNotPushOnly
|
||||
|
||||
// ErrSigNullDummy is returned when the ScriptStrictMultiSig flag is set
|
||||
// and a multisig script has anything other than 0 for the extra dummy
|
||||
// argument.
|
||||
ErrSigNullDummy
|
||||
|
||||
// ErrPubKeyType is returned when the ScriptVerifyStrictEncoding
|
||||
// flag is set and the script contains invalid public keys.
|
||||
ErrPubKeyType
|
||||
|
||||
// ErrCleanStack is returned when the ScriptVerifyCleanStack flag
|
||||
// is set, and after evalution, the stack does not contain only a
|
||||
// single element.
|
||||
ErrCleanStack
|
||||
|
||||
// ErrNullFail is returned when the ScriptVerifyNullFail flag is
|
||||
// set and signatures are not empty on failed checksig or checkmultisig
|
||||
// operations.
|
||||
ErrNullFail
|
||||
|
||||
// ErrWitnessMalleated is returned if ScriptVerifyWitness is set and a
|
||||
// native p2wsh program is encountered which has a non-empty sigScript.
|
||||
ErrWitnessMalleated
|
||||
|
||||
// ErrWitnessMalleatedP2SH is returned if ScriptVerifyWitness if set
|
||||
// and the validation logic for nested p2sh encounters a sigScript
|
||||
// which isn't *exactyl* a datapush of the witness program.
|
||||
ErrWitnessMalleatedP2SH
|
||||
|
||||
// -------------------------------
|
||||
// Failures related to soft forks.
|
||||
// -------------------------------
|
||||
|
||||
// ErrDiscourageUpgradableNOPs is returned when the
|
||||
// ScriptDiscourageUpgradableNops flag is set and a NOP opcode is
|
||||
// encountered in a script.
|
||||
ErrDiscourageUpgradableNOPs
|
||||
|
||||
// ErrNegativeLockTime is returned when a script contains an opcode that
|
||||
// interprets a negative lock time.
|
||||
ErrNegativeLockTime
|
||||
|
||||
// ErrUnsatisfiedLockTime is returned when a script contains an opcode
|
||||
// that involves a lock time and the required lock time has not been
|
||||
// reached.
|
||||
ErrUnsatisfiedLockTime
|
||||
|
||||
// ErrMinimalIf is returned if ScriptVerifyWitness is set and the
|
||||
// operand of an OP_IF/OP_NOF_IF are not either an empty vector or
|
||||
// [0x01].
|
||||
ErrMinimalIf
|
||||
|
||||
// ErrDiscourageUpgradableWitnessProgram is returned if
|
||||
// ScriptVerifyWitness is set and the versino of an executing witness
|
||||
// program is outside the set of currently defined witness program
|
||||
// vesions.
|
||||
ErrDiscourageUpgradableWitnessProgram
|
||||
|
||||
// ----------------------------------------
|
||||
// Failures related to segregated witness.
|
||||
// ----------------------------------------
|
||||
|
||||
// ErrWitnessProgramEmpty is returned if ScriptVerifyWitness is set and
|
||||
// the witness stack itself is empty.
|
||||
ErrWitnessProgramEmpty
|
||||
|
||||
// ErrWitnessProgramMismatch is returned if ScriptVerifyWitness is set
|
||||
// and the witness itself for a p2wkh witness program isn't *exactly* 2
|
||||
// items or if the witness for a p2wsh isn't the sha255 of the witness
|
||||
// script.
|
||||
ErrWitnessProgramMismatch
|
||||
|
||||
// ErrWitnessProgramWrongLength is returned if ScriptVerifyWitness is
|
||||
// set and the length of the witness program violates the length as
|
||||
// dictated by the current witness version.
|
||||
ErrWitnessProgramWrongLength
|
||||
|
||||
// ErrWitnessUnexpected is returned if ScriptVerifyWitness is set and a
|
||||
// transaction includes witness data but doesn't spend an which is a
|
||||
// witness program (nested or native).
|
||||
ErrWitnessUnexpected
|
||||
|
||||
// ErrWitnessPubKeyType is returned if ScriptVerifyWitness is set and
|
||||
// the public key used in either a check-sig or check-multi-sig isn't
|
||||
// serialized in a compressed format.
|
||||
ErrWitnessPubKeyType
|
||||
|
||||
// numErrorCodes is the maximum error code number used in tests. This
|
||||
// entry MUST be the last entry in the enum.
|
||||
numErrorCodes
|
||||
)
|
||||
|
||||
// Map of ErrorCode values back to their constant names for pretty printing.
|
||||
var errorCodeStrings = map[ErrorCode]string{
|
||||
ErrInternal: "ErrInternal",
|
||||
ErrInvalidFlags: "ErrInvalidFlags",
|
||||
ErrInvalidIndex: "ErrInvalidIndex",
|
||||
ErrUnsupportedAddress: "ErrUnsupportedAddress",
|
||||
ErrNotMultisigScript: "ErrNotMultisigScript",
|
||||
ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs",
|
||||
ErrTooMuchNullData: "ErrTooMuchNullData",
|
||||
ErrEarlyReturn: "ErrEarlyReturn",
|
||||
ErrEmptyStack: "ErrEmptyStack",
|
||||
ErrEvalFalse: "ErrEvalFalse",
|
||||
ErrScriptUnfinished: "ErrScriptUnfinished",
|
||||
ErrInvalidProgramCounter: "ErrInvalidProgramCounter",
|
||||
ErrScriptTooBig: "ErrScriptTooBig",
|
||||
ErrElementTooBig: "ErrElementTooBig",
|
||||
ErrTooManyOperations: "ErrTooManyOperations",
|
||||
ErrStackOverflow: "ErrStackOverflow",
|
||||
ErrInvalidPubKeyCount: "ErrInvalidPubKeyCount",
|
||||
ErrInvalidSignatureCount: "ErrInvalidSignatureCount",
|
||||
ErrNumberTooBig: "ErrNumberTooBig",
|
||||
ErrVerify: "ErrVerify",
|
||||
ErrEqualVerify: "ErrEqualVerify",
|
||||
ErrNumEqualVerify: "ErrNumEqualVerify",
|
||||
ErrCheckSigVerify: "ErrCheckSigVerify",
|
||||
ErrCheckMultiSigVerify: "ErrCheckMultiSigVerify",
|
||||
ErrDisabledOpcode: "ErrDisabledOpcode",
|
||||
ErrReservedOpcode: "ErrReservedOpcode",
|
||||
ErrMalformedPush: "ErrMalformedPush",
|
||||
ErrInvalidStackOperation: "ErrInvalidStackOperation",
|
||||
ErrUnbalancedConditional: "ErrUnbalancedConditional",
|
||||
ErrMinimalData: "ErrMinimalData",
|
||||
ErrInvalidSigHashType: "ErrInvalidSigHashType",
|
||||
ErrSigTooShort: "ErrSigTooShort",
|
||||
ErrSigTooLong: "ErrSigTooLong",
|
||||
ErrSigInvalidSeqID: "ErrSigInvalidSeqID",
|
||||
ErrSigInvalidDataLen: "ErrSigInvalidDataLen",
|
||||
ErrSigMissingSTypeID: "ErrSigMissingSTypeID",
|
||||
ErrSigMissingSLen: "ErrSigMissingSLen",
|
||||
ErrSigInvalidSLen: "ErrSigInvalidSLen",
|
||||
ErrSigInvalidRIntID: "ErrSigInvalidRIntID",
|
||||
ErrSigZeroRLen: "ErrSigZeroRLen",
|
||||
ErrSigNegativeR: "ErrSigNegativeR",
|
||||
ErrSigTooMuchRPadding: "ErrSigTooMuchRPadding",
|
||||
ErrSigInvalidSIntID: "ErrSigInvalidSIntID",
|
||||
ErrSigZeroSLen: "ErrSigZeroSLen",
|
||||
ErrSigNegativeS: "ErrSigNegativeS",
|
||||
ErrSigTooMuchSPadding: "ErrSigTooMuchSPadding",
|
||||
ErrSigHighS: "ErrSigHighS",
|
||||
ErrNotPushOnly: "ErrNotPushOnly",
|
||||
ErrSigNullDummy: "ErrSigNullDummy",
|
||||
ErrPubKeyType: "ErrPubKeyType",
|
||||
ErrCleanStack: "ErrCleanStack",
|
||||
ErrNullFail: "ErrNullFail",
|
||||
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
||||
ErrNegativeLockTime: "ErrNegativeLockTime",
|
||||
ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime",
|
||||
ErrWitnessProgramEmpty: "ErrWitnessProgramEmpty",
|
||||
ErrWitnessProgramMismatch: "ErrWitnessProgramMismatch",
|
||||
ErrWitnessProgramWrongLength: "ErrWitnessProgramWrongLength",
|
||||
ErrWitnessMalleated: "ErrWitnessMalleated",
|
||||
ErrWitnessMalleatedP2SH: "ErrWitnessMalleatedP2SH",
|
||||
ErrWitnessUnexpected: "ErrWitnessUnexpected",
|
||||
ErrMinimalIf: "ErrMinimalIf",
|
||||
ErrWitnessPubKeyType: "ErrWitnessPubKeyType",
|
||||
ErrDiscourageUpgradableWitnessProgram: "ErrDiscourageUpgradableWitnessProgram",
|
||||
}
|
||||
|
||||
// String returns the ErrorCode as a human-readable name.
|
||||
func (e ErrorCode) String() string {
|
||||
if s := errorCodeStrings[e]; s != "" {
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf("Unknown ErrorCode (%d)", int(e))
|
||||
}
|
||||
|
||||
// Error identifies a script-related error. It is used to indicate three
|
||||
// classes of errors:
|
||||
// 1) Script execution failures due to violating one of the many requirements
|
||||
// imposed by the script engine or evaluating to false
|
||||
// 2) Improper API usage by callers
|
||||
// 3) Internal consistency check failures
|
||||
//
|
||||
// The caller can use type assertions on the returned errors to access the
|
||||
// ErrorCode field to ascertain the specific reason for the error. As an
|
||||
// additional convenience, the caller may make use of the IsErrorCode function
|
||||
// to check for a specific error code.
|
||||
type Error struct {
|
||||
ErrorCode ErrorCode
|
||||
Description string
|
||||
}
|
||||
|
||||
// Error satisfies the error interface and prints human-readable errors.
|
||||
func (e Error) Error() string {
|
||||
return e.Description
|
||||
}
|
||||
|
||||
// scriptError creates an Error given a set of arguments.
|
||||
func scriptError(c ErrorCode, desc string) Error {
|
||||
return Error{ErrorCode: c, Description: desc}
|
||||
}
|
||||
|
||||
// IsErrorCode returns whether or not the provided error is a script error with
|
||||
// the provided error code.
|
||||
func IsErrorCode(err error, c ErrorCode) bool {
|
||||
serr, ok := err.(Error)
|
||||
return ok && serr.ErrorCode == c
|
||||
}
|
||||
89
vendor/github.com/btcsuite/btcd/txscript/hashcache.go
generated
vendored
Normal file
89
vendor/github.com/btcsuite/btcd/txscript/hashcache.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
// TxSigHashes houses the partial set of sighashes introduced within BIP0143.
|
||||
// This partial set of sighashes may be re-used within each input across a
|
||||
// transaction when validating all inputs. As a result, validation complexity
|
||||
// for SigHashAll can be reduced by a polynomial factor.
|
||||
type TxSigHashes struct {
|
||||
HashPrevOuts chainhash.Hash
|
||||
HashSequence chainhash.Hash
|
||||
HashOutputs chainhash.Hash
|
||||
}
|
||||
|
||||
// NewTxSigHashes computes, and returns the cached sighashes of the given
|
||||
// transaction.
|
||||
func NewTxSigHashes(tx *wire.MsgTx) *TxSigHashes {
|
||||
return &TxSigHashes{
|
||||
HashPrevOuts: calcHashPrevOuts(tx),
|
||||
HashSequence: calcHashSequence(tx),
|
||||
HashOutputs: calcHashOutputs(tx),
|
||||
}
|
||||
}
|
||||
|
||||
// HashCache houses a set of partial sighashes keyed by txid. The set of partial
|
||||
// sighashes are those introduced within BIP0143 by the new more efficient
|
||||
// sighash digest calculation algorithm. Using this threadsafe shared cache,
|
||||
// multiple goroutines can safely re-use the pre-computed partial sighashes
|
||||
// speeding up validation time amongst all inputs found within a block.
|
||||
type HashCache struct {
|
||||
sigHashes map[chainhash.Hash]*TxSigHashes
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// NewHashCache returns a new instance of the HashCache given a maximum number
|
||||
// of entries which may exist within it at anytime.
|
||||
func NewHashCache(maxSize uint) *HashCache {
|
||||
return &HashCache{
|
||||
sigHashes: make(map[chainhash.Hash]*TxSigHashes, maxSize),
|
||||
}
|
||||
}
|
||||
|
||||
// AddSigHashes computes, then adds the partial sighashes for the passed
|
||||
// transaction.
|
||||
func (h *HashCache) AddSigHashes(tx *wire.MsgTx) {
|
||||
h.Lock()
|
||||
h.sigHashes[tx.TxHash()] = NewTxSigHashes(tx)
|
||||
h.Unlock()
|
||||
}
|
||||
|
||||
// ContainsHashes returns true if the partial sighashes for the passed
|
||||
// transaction currently exist within the HashCache, and false otherwise.
|
||||
func (h *HashCache) ContainsHashes(txid *chainhash.Hash) bool {
|
||||
h.RLock()
|
||||
_, found := h.sigHashes[*txid]
|
||||
h.RUnlock()
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
// GetSigHashes possibly returns the previously cached partial sighashes for
|
||||
// the passed transaction. This function also returns an additional boolean
|
||||
// value indicating if the sighashes for the passed transaction were found to
|
||||
// be present within the HashCache.
|
||||
func (h *HashCache) GetSigHashes(txid *chainhash.Hash) (*TxSigHashes, bool) {
|
||||
h.RLock()
|
||||
item, found := h.sigHashes[*txid]
|
||||
h.RUnlock()
|
||||
|
||||
return item, found
|
||||
}
|
||||
|
||||
// PurgeSigHashes removes all partial sighashes from the HashCache belonging to
|
||||
// the passed transaction.
|
||||
func (h *HashCache) PurgeSigHashes(txid *chainhash.Hash) {
|
||||
h.Lock()
|
||||
delete(h.sigHashes, *txid)
|
||||
h.Unlock()
|
||||
}
|
||||
43
vendor/github.com/btcsuite/btcd/txscript/log.go
generated
vendored
Normal file
43
vendor/github.com/btcsuite/btcd/txscript/log.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2013-2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btclog"
|
||||
)
|
||||
|
||||
// log is a logger that is initialized with no output filters. This
|
||||
// means the package will not perform any logging by default until the caller
|
||||
// requests it.
|
||||
var log btclog.Logger
|
||||
|
||||
// The default amount of logging is none.
|
||||
func init() {
|
||||
DisableLog()
|
||||
}
|
||||
|
||||
// DisableLog disables all library log output. Logging output is disabled
|
||||
// by default until UseLogger is called.
|
||||
func DisableLog() {
|
||||
log = btclog.Disabled
|
||||
}
|
||||
|
||||
// UseLogger uses a specified Logger to output package logging info.
|
||||
func UseLogger(logger btclog.Logger) {
|
||||
log = logger
|
||||
}
|
||||
|
||||
// LogClosure is a closure that can be printed with %v to be used to
|
||||
// generate expensive-to-create data for a detailed log level and avoid doing
|
||||
// the work if the data isn't printed.
|
||||
type logClosure func() string
|
||||
|
||||
func (c logClosure) String() string {
|
||||
return c()
|
||||
}
|
||||
|
||||
func newLogClosure(c func() string) logClosure {
|
||||
return logClosure(c)
|
||||
}
|
||||
2447
vendor/github.com/btcsuite/btcd/txscript/opcode.go
generated
vendored
Normal file
2447
vendor/github.com/btcsuite/btcd/txscript/opcode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
279
vendor/github.com/btcsuite/btcd/txscript/pkscript.go
generated
vendored
Normal file
279
vendor/github.com/btcsuite/btcd/txscript/pkscript.go
generated
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
)
|
||||
|
||||
const (
|
||||
// minPubKeyHashSigScriptLen is the minimum length of a signature script
|
||||
// that spends a P2PKH output. The length is composed of the following:
|
||||
// Signature length (1 byte)
|
||||
// Signature (min 8 bytes)
|
||||
// Signature hash type (1 byte)
|
||||
// Public key length (1 byte)
|
||||
// Public key (33 byte)
|
||||
minPubKeyHashSigScriptLen = 1 + btcec.MinSigLen + 1 + 1 + 33
|
||||
|
||||
// maxPubKeyHashSigScriptLen is the maximum length of a signature script
|
||||
// that spends a P2PKH output. The length is composed of the following:
|
||||
// Signature length (1 byte)
|
||||
// Signature (max 72 bytes)
|
||||
// Signature hash type (1 byte)
|
||||
// Public key length (1 byte)
|
||||
// Public key (33 byte)
|
||||
maxPubKeyHashSigScriptLen = 1 + 72 + 1 + 1 + 33
|
||||
|
||||
// compressedPubKeyLen is the length in bytes of a compressed public
|
||||
// key.
|
||||
compressedPubKeyLen = 33
|
||||
|
||||
// pubKeyHashLen is the length of a P2PKH script.
|
||||
pubKeyHashLen = 25
|
||||
|
||||
// witnessV0PubKeyHashLen is the length of a P2WPKH script.
|
||||
witnessV0PubKeyHashLen = 22
|
||||
|
||||
// scriptHashLen is the length of a P2SH script.
|
||||
scriptHashLen = 23
|
||||
|
||||
// witnessV0ScriptHashLen is the length of a P2WSH script.
|
||||
witnessV0ScriptHashLen = 34
|
||||
|
||||
// maxLen is the maximum script length supported by ParsePkScript.
|
||||
maxLen = witnessV0ScriptHashLen
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrUnsupportedScriptType is an error returned when we attempt to
|
||||
// parse/re-compute an output script into a PkScript struct.
|
||||
ErrUnsupportedScriptType = errors.New("unsupported script type")
|
||||
)
|
||||
|
||||
// PkScript is a wrapper struct around a byte array, allowing it to be used
|
||||
// as a map index.
|
||||
type PkScript struct {
|
||||
// class is the type of the script encoded within the byte array. This
|
||||
// is used to determine the correct length of the script within the byte
|
||||
// array.
|
||||
class ScriptClass
|
||||
|
||||
// script is the script contained within a byte array. If the script is
|
||||
// smaller than the length of the byte array, it will be padded with 0s
|
||||
// at the end.
|
||||
script [maxLen]byte
|
||||
}
|
||||
|
||||
// ParsePkScript parses an output script into the PkScript struct.
|
||||
// ErrUnsupportedScriptType is returned when attempting to parse an unsupported
|
||||
// script type.
|
||||
func ParsePkScript(pkScript []byte) (PkScript, error) {
|
||||
var outputScript PkScript
|
||||
scriptClass, _, _, err := ExtractPkScriptAddrs(
|
||||
pkScript, &chaincfg.MainNetParams,
|
||||
)
|
||||
if err != nil {
|
||||
return outputScript, fmt.Errorf("unable to parse script type: "+
|
||||
"%v", err)
|
||||
}
|
||||
|
||||
if !isSupportedScriptType(scriptClass) {
|
||||
return outputScript, ErrUnsupportedScriptType
|
||||
}
|
||||
|
||||
outputScript.class = scriptClass
|
||||
copy(outputScript.script[:], pkScript)
|
||||
|
||||
return outputScript, nil
|
||||
}
|
||||
|
||||
// isSupportedScriptType determines whether the script type is supported by the
|
||||
// PkScript struct.
|
||||
func isSupportedScriptType(class ScriptClass) bool {
|
||||
switch class {
|
||||
case PubKeyHashTy, WitnessV0PubKeyHashTy, ScriptHashTy,
|
||||
WitnessV0ScriptHashTy:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Class returns the script type.
|
||||
func (s PkScript) Class() ScriptClass {
|
||||
return s.class
|
||||
}
|
||||
|
||||
// Script returns the script as a byte slice without any padding.
|
||||
func (s PkScript) Script() []byte {
|
||||
var script []byte
|
||||
|
||||
switch s.class {
|
||||
case PubKeyHashTy:
|
||||
script = make([]byte, pubKeyHashLen)
|
||||
copy(script, s.script[:pubKeyHashLen])
|
||||
|
||||
case WitnessV0PubKeyHashTy:
|
||||
script = make([]byte, witnessV0PubKeyHashLen)
|
||||
copy(script, s.script[:witnessV0PubKeyHashLen])
|
||||
|
||||
case ScriptHashTy:
|
||||
script = make([]byte, scriptHashLen)
|
||||
copy(script, s.script[:scriptHashLen])
|
||||
|
||||
case WitnessV0ScriptHashTy:
|
||||
script = make([]byte, witnessV0ScriptHashLen)
|
||||
copy(script, s.script[:witnessV0ScriptHashLen])
|
||||
|
||||
default:
|
||||
// Unsupported script type.
|
||||
return nil
|
||||
}
|
||||
|
||||
return script
|
||||
}
|
||||
|
||||
// Address encodes the script into an address for the given chain.
|
||||
func (s PkScript) Address(chainParams *chaincfg.Params) (btcutil.Address, error) {
|
||||
_, addrs, _, err := ExtractPkScriptAddrs(s.Script(), chainParams)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse address: %v", err)
|
||||
}
|
||||
|
||||
return addrs[0], nil
|
||||
}
|
||||
|
||||
// String returns a hex-encoded string representation of the script.
|
||||
func (s PkScript) String() string {
|
||||
str, _ := DisasmString(s.Script())
|
||||
return str
|
||||
}
|
||||
|
||||
// ComputePkScript computes the script of an output by looking at the spending
|
||||
// input's signature script or witness.
|
||||
//
|
||||
// NOTE: Only P2PKH, P2SH, P2WSH, and P2WPKH redeem scripts are supported.
|
||||
func ComputePkScript(sigScript []byte, witness wire.TxWitness) (PkScript, error) {
|
||||
switch {
|
||||
case len(sigScript) > 0:
|
||||
return computeNonWitnessPkScript(sigScript)
|
||||
case len(witness) > 0:
|
||||
return computeWitnessPkScript(witness)
|
||||
default:
|
||||
return PkScript{}, ErrUnsupportedScriptType
|
||||
}
|
||||
}
|
||||
|
||||
// computeNonWitnessPkScript computes the script of an output by looking at the
|
||||
// spending input's signature script.
|
||||
func computeNonWitnessPkScript(sigScript []byte) (PkScript, error) {
|
||||
switch {
|
||||
// Since we only support P2PKH and P2SH scripts as the only non-witness
|
||||
// script types, we should expect to see a push only script.
|
||||
case !IsPushOnlyScript(sigScript):
|
||||
return PkScript{}, ErrUnsupportedScriptType
|
||||
|
||||
// If a signature script is provided with a length long enough to
|
||||
// represent a P2PKH script, then we'll attempt to parse the compressed
|
||||
// public key from it.
|
||||
case len(sigScript) >= minPubKeyHashSigScriptLen &&
|
||||
len(sigScript) <= maxPubKeyHashSigScriptLen:
|
||||
|
||||
// The public key should be found as the last part of the
|
||||
// signature script. We'll attempt to parse it to ensure this is
|
||||
// a P2PKH redeem script.
|
||||
pubKey := sigScript[len(sigScript)-compressedPubKeyLen:]
|
||||
if btcec.IsCompressedPubKey(pubKey) {
|
||||
pubKeyHash := hash160(pubKey)
|
||||
script, err := payToPubKeyHashScript(pubKeyHash)
|
||||
if err != nil {
|
||||
return PkScript{}, err
|
||||
}
|
||||
|
||||
pkScript := PkScript{class: PubKeyHashTy}
|
||||
copy(pkScript.script[:], script)
|
||||
return pkScript, nil
|
||||
}
|
||||
|
||||
fallthrough
|
||||
|
||||
// If we failed to parse a compressed public key from the script in the
|
||||
// case above, or if the script length is not that of a P2PKH one, we
|
||||
// can assume it's a P2SH signature script.
|
||||
default:
|
||||
// The redeem script will always be the last data push of the
|
||||
// signature script, so we'll parse the script into opcodes to
|
||||
// obtain it.
|
||||
parsedOpcodes, err := parseScript(sigScript)
|
||||
if err != nil {
|
||||
return PkScript{}, err
|
||||
}
|
||||
redeemScript := parsedOpcodes[len(parsedOpcodes)-1].data
|
||||
|
||||
scriptHash := hash160(redeemScript)
|
||||
script, err := payToScriptHashScript(scriptHash)
|
||||
if err != nil {
|
||||
return PkScript{}, err
|
||||
}
|
||||
|
||||
pkScript := PkScript{class: ScriptHashTy}
|
||||
copy(pkScript.script[:], script)
|
||||
return pkScript, nil
|
||||
}
|
||||
}
|
||||
|
||||
// computeWitnessPkScript computes the script of an output by looking at the
|
||||
// spending input's witness.
|
||||
func computeWitnessPkScript(witness wire.TxWitness) (PkScript, error) {
|
||||
// We'll use the last item of the witness stack to determine the proper
|
||||
// witness type.
|
||||
lastWitnessItem := witness[len(witness)-1]
|
||||
|
||||
var pkScript PkScript
|
||||
switch {
|
||||
// If the witness stack has a size of 2 and its last item is a
|
||||
// compressed public key, then this is a P2WPKH witness.
|
||||
case len(witness) == 2 && len(lastWitnessItem) == compressedPubKeyLen:
|
||||
pubKeyHash := hash160(lastWitnessItem)
|
||||
script, err := payToWitnessPubKeyHashScript(pubKeyHash)
|
||||
if err != nil {
|
||||
return pkScript, err
|
||||
}
|
||||
|
||||
pkScript.class = WitnessV0PubKeyHashTy
|
||||
copy(pkScript.script[:], script)
|
||||
|
||||
// For any other witnesses, we'll assume it's a P2WSH witness.
|
||||
default:
|
||||
scriptHash := sha256.Sum256(lastWitnessItem)
|
||||
script, err := payToWitnessScriptHashScript(scriptHash[:])
|
||||
if err != nil {
|
||||
return pkScript, err
|
||||
}
|
||||
|
||||
pkScript.class = WitnessV0ScriptHashTy
|
||||
copy(pkScript.script[:], script)
|
||||
}
|
||||
|
||||
return pkScript, nil
|
||||
}
|
||||
|
||||
// hash160 returns the RIPEMD160 hash of the SHA-256 HASH of the given data.
|
||||
func hash160(data []byte) []byte {
|
||||
h := sha256.Sum256(data)
|
||||
return ripemd160h(h[:])
|
||||
}
|
||||
|
||||
// ripemd160h returns the RIPEMD160 hash of the given data.
|
||||
func ripemd160h(data []byte) []byte {
|
||||
h := ripemd160.New()
|
||||
h.Write(data)
|
||||
return h.Sum(nil)
|
||||
}
|
||||
860
vendor/github.com/btcsuite/btcd/txscript/script.go
generated
vendored
Normal file
860
vendor/github.com/btcsuite/btcd/txscript/script.go
generated
vendored
Normal file
@@ -0,0 +1,860 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
// Bip16Activation is the timestamp where BIP0016 is valid to use in the
|
||||
// blockchain. To be used to determine if BIP0016 should be called for or not.
|
||||
// This timestamp corresponds to Sun Apr 1 00:00:00 UTC 2012.
|
||||
var Bip16Activation = time.Unix(1333238400, 0)
|
||||
|
||||
// SigHashType represents hash type bits at the end of a signature.
|
||||
type SigHashType uint32
|
||||
|
||||
// Hash type bits from the end of a signature.
|
||||
const (
|
||||
SigHashOld SigHashType = 0x0
|
||||
SigHashAll SigHashType = 0x1
|
||||
SigHashNone SigHashType = 0x2
|
||||
SigHashSingle SigHashType = 0x3
|
||||
SigHashAnyOneCanPay SigHashType = 0x80
|
||||
|
||||
// sigHashMask defines the number of bits of the hash type which is used
|
||||
// to identify which outputs are signed.
|
||||
sigHashMask = 0x1f
|
||||
)
|
||||
|
||||
// These are the constants specified for maximums in individual scripts.
|
||||
const (
|
||||
MaxOpsPerScript = 201 // Max number of non-push operations.
|
||||
MaxPubKeysPerMultiSig = 20 // Multisig can't have more sigs than this.
|
||||
MaxScriptElementSize = 520 // Max bytes pushable to the stack.
|
||||
)
|
||||
|
||||
// isSmallInt returns whether or not the opcode is considered a small integer,
|
||||
// which is an OP_0, or OP_1 through OP_16.
|
||||
func isSmallInt(op *opcode) bool {
|
||||
if op.value == OP_0 || (op.value >= OP_1 && op.value <= OP_16) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isScriptHash returns true if the script passed is a pay-to-script-hash
|
||||
// transaction, false otherwise.
|
||||
func isScriptHash(pops []parsedOpcode) bool {
|
||||
return len(pops) == 3 &&
|
||||
pops[0].opcode.value == OP_HASH160 &&
|
||||
pops[1].opcode.value == OP_DATA_20 &&
|
||||
pops[2].opcode.value == OP_EQUAL
|
||||
}
|
||||
|
||||
// IsPayToScriptHash returns true if the script is in the standard
|
||||
// pay-to-script-hash (P2SH) format, false otherwise.
|
||||
func IsPayToScriptHash(script []byte) bool {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isScriptHash(pops)
|
||||
}
|
||||
|
||||
// isWitnessScriptHash returns true if the passed script is a
|
||||
// pay-to-witness-script-hash transaction, false otherwise.
|
||||
func isWitnessScriptHash(pops []parsedOpcode) bool {
|
||||
return len(pops) == 2 &&
|
||||
pops[0].opcode.value == OP_0 &&
|
||||
pops[1].opcode.value == OP_DATA_32
|
||||
}
|
||||
|
||||
// IsPayToWitnessScriptHash returns true if the is in the standard
|
||||
// pay-to-witness-script-hash (P2WSH) format, false otherwise.
|
||||
func IsPayToWitnessScriptHash(script []byte) bool {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isWitnessScriptHash(pops)
|
||||
}
|
||||
|
||||
// IsPayToWitnessPubKeyHash returns true if the is in the standard
|
||||
// pay-to-witness-pubkey-hash (P2WKH) format, false otherwise.
|
||||
func IsPayToWitnessPubKeyHash(script []byte) bool {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isWitnessPubKeyHash(pops)
|
||||
}
|
||||
|
||||
// isWitnessPubKeyHash returns true if the passed script is a
|
||||
// pay-to-witness-pubkey-hash, and false otherwise.
|
||||
func isWitnessPubKeyHash(pops []parsedOpcode) bool {
|
||||
return len(pops) == 2 &&
|
||||
pops[0].opcode.value == OP_0 &&
|
||||
pops[1].opcode.value == OP_DATA_20
|
||||
}
|
||||
|
||||
// IsWitnessProgram returns true if the passed script is a valid witness
|
||||
// program which is encoded according to the passed witness program version. A
|
||||
// witness program must be a small integer (from 0-16), followed by 2-40 bytes
|
||||
// of pushed data.
|
||||
func IsWitnessProgram(script []byte) bool {
|
||||
// The length of the script must be between 4 and 42 bytes. The
|
||||
// smallest program is the witness version, followed by a data push of
|
||||
// 2 bytes. The largest allowed witness program has a data push of
|
||||
// 40-bytes.
|
||||
if len(script) < 4 || len(script) > 42 {
|
||||
return false
|
||||
}
|
||||
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return isWitnessProgram(pops)
|
||||
}
|
||||
|
||||
// isWitnessProgram returns true if the passed script is a witness program, and
|
||||
// false otherwise. A witness program MUST adhere to the following constraints:
|
||||
// there must be exactly two pops (program version and the program itself), the
|
||||
// first opcode MUST be a small integer (0-16), the push data MUST be
|
||||
// canonical, and finally the size of the push data must be between 2 and 40
|
||||
// bytes.
|
||||
func isWitnessProgram(pops []parsedOpcode) bool {
|
||||
return len(pops) == 2 &&
|
||||
isSmallInt(pops[0].opcode) &&
|
||||
canonicalPush(pops[1]) &&
|
||||
(len(pops[1].data) >= 2 && len(pops[1].data) <= 40)
|
||||
}
|
||||
|
||||
// ExtractWitnessProgramInfo attempts to extract the witness program version,
|
||||
// as well as the witness program itself from the passed script.
|
||||
func ExtractWitnessProgramInfo(script []byte) (int, []byte, error) {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
// If at this point, the scripts doesn't resemble a witness program,
|
||||
// then we'll exit early as there isn't a valid version or program to
|
||||
// extract.
|
||||
if !isWitnessProgram(pops) {
|
||||
return 0, nil, fmt.Errorf("script is not a witness program, " +
|
||||
"unable to extract version or witness program")
|
||||
}
|
||||
|
||||
witnessVersion := asSmallInt(pops[0].opcode)
|
||||
witnessProgram := pops[1].data
|
||||
|
||||
return witnessVersion, witnessProgram, nil
|
||||
}
|
||||
|
||||
// isPushOnly returns true if the script only pushes data, false otherwise.
|
||||
func isPushOnly(pops []parsedOpcode) bool {
|
||||
// NOTE: This function does NOT verify opcodes directly since it is
|
||||
// internal and is only called with parsed opcodes for scripts that did
|
||||
// not have any parse errors. Thus, consensus is properly maintained.
|
||||
|
||||
for _, pop := range pops {
|
||||
// All opcodes up to OP_16 are data push instructions.
|
||||
// NOTE: This does consider OP_RESERVED to be a data push
|
||||
// instruction, but execution of OP_RESERVED will fail anyways
|
||||
// and matches the behavior required by consensus.
|
||||
if pop.opcode.value > OP_16 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsPushOnlyScript returns whether or not the passed script only pushes data.
|
||||
//
|
||||
// False will be returned when the script does not parse.
|
||||
func IsPushOnlyScript(script []byte) bool {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isPushOnly(pops)
|
||||
}
|
||||
|
||||
// parseScriptTemplate is the same as parseScript but allows the passing of the
|
||||
// template list for testing purposes. When there are parse errors, it returns
|
||||
// the list of parsed opcodes up to the point of failure along with the error.
|
||||
func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, error) {
|
||||
retScript := make([]parsedOpcode, 0, len(script))
|
||||
for i := 0; i < len(script); {
|
||||
instr := script[i]
|
||||
op := &opcodes[instr]
|
||||
pop := parsedOpcode{opcode: op}
|
||||
|
||||
// Parse data out of instruction.
|
||||
switch {
|
||||
// No additional data. Note that some of the opcodes, notably
|
||||
// OP_1NEGATE, OP_0, and OP_[1-16] represent the data
|
||||
// themselves.
|
||||
case op.length == 1:
|
||||
i++
|
||||
|
||||
// Data pushes of specific lengths -- OP_DATA_[1-75].
|
||||
case op.length > 1:
|
||||
if len(script[i:]) < op.length {
|
||||
str := fmt.Sprintf("opcode %s requires %d "+
|
||||
"bytes, but script only has %d remaining",
|
||||
op.name, op.length, len(script[i:]))
|
||||
return retScript, scriptError(ErrMalformedPush,
|
||||
str)
|
||||
}
|
||||
|
||||
// Slice out the data.
|
||||
pop.data = script[i+1 : i+op.length]
|
||||
i += op.length
|
||||
|
||||
// Data pushes with parsed lengths -- OP_PUSHDATAP{1,2,4}.
|
||||
case op.length < 0:
|
||||
var l uint
|
||||
off := i + 1
|
||||
|
||||
if len(script[off:]) < -op.length {
|
||||
str := fmt.Sprintf("opcode %s requires %d "+
|
||||
"bytes, but script only has %d remaining",
|
||||
op.name, -op.length, len(script[off:]))
|
||||
return retScript, scriptError(ErrMalformedPush,
|
||||
str)
|
||||
}
|
||||
|
||||
// Next -length bytes are little endian length of data.
|
||||
switch op.length {
|
||||
case -1:
|
||||
l = uint(script[off])
|
||||
case -2:
|
||||
l = ((uint(script[off+1]) << 8) |
|
||||
uint(script[off]))
|
||||
case -4:
|
||||
l = ((uint(script[off+3]) << 24) |
|
||||
(uint(script[off+2]) << 16) |
|
||||
(uint(script[off+1]) << 8) |
|
||||
uint(script[off]))
|
||||
default:
|
||||
str := fmt.Sprintf("invalid opcode length %d",
|
||||
op.length)
|
||||
return retScript, scriptError(ErrMalformedPush,
|
||||
str)
|
||||
}
|
||||
|
||||
// Move offset to beginning of the data.
|
||||
off += -op.length
|
||||
|
||||
// Disallow entries that do not fit script or were
|
||||
// sign extended.
|
||||
if int(l) > len(script[off:]) || int(l) < 0 {
|
||||
str := fmt.Sprintf("opcode %s pushes %d bytes, "+
|
||||
"but script only has %d remaining",
|
||||
op.name, int(l), len(script[off:]))
|
||||
return retScript, scriptError(ErrMalformedPush,
|
||||
str)
|
||||
}
|
||||
|
||||
pop.data = script[off : off+int(l)]
|
||||
i += 1 - op.length + int(l)
|
||||
}
|
||||
|
||||
retScript = append(retScript, pop)
|
||||
}
|
||||
|
||||
return retScript, nil
|
||||
}
|
||||
|
||||
// parseScript preparses the script in bytes into a list of parsedOpcodes while
|
||||
// applying a number of sanity checks.
|
||||
func parseScript(script []byte) ([]parsedOpcode, error) {
|
||||
return parseScriptTemplate(script, &opcodeArray)
|
||||
}
|
||||
|
||||
// unparseScript reversed the action of parseScript and returns the
|
||||
// parsedOpcodes as a list of bytes
|
||||
func unparseScript(pops []parsedOpcode) ([]byte, error) {
|
||||
script := make([]byte, 0, len(pops))
|
||||
for _, pop := range pops {
|
||||
b, err := pop.bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
script = append(script, b...)
|
||||
}
|
||||
return script, nil
|
||||
}
|
||||
|
||||
// DisasmString formats a disassembled script for one line printing. When the
|
||||
// script fails to parse, the returned string will contain the disassembled
|
||||
// script up to the point the failure occurred along with the string '[error]'
|
||||
// appended. In addition, the reason the script failed to parse is returned
|
||||
// if the caller wants more information about the failure.
|
||||
func DisasmString(buf []byte) (string, error) {
|
||||
var disbuf bytes.Buffer
|
||||
opcodes, err := parseScript(buf)
|
||||
for _, pop := range opcodes {
|
||||
disbuf.WriteString(pop.print(true))
|
||||
disbuf.WriteByte(' ')
|
||||
}
|
||||
if disbuf.Len() > 0 {
|
||||
disbuf.Truncate(disbuf.Len() - 1)
|
||||
}
|
||||
if err != nil {
|
||||
disbuf.WriteString("[error]")
|
||||
}
|
||||
return disbuf.String(), err
|
||||
}
|
||||
|
||||
// removeOpcode will remove any opcode matching ``opcode'' from the opcode
|
||||
// stream in pkscript
|
||||
func removeOpcode(pkscript []parsedOpcode, opcode byte) []parsedOpcode {
|
||||
retScript := make([]parsedOpcode, 0, len(pkscript))
|
||||
for _, pop := range pkscript {
|
||||
if pop.opcode.value != opcode {
|
||||
retScript = append(retScript, pop)
|
||||
}
|
||||
}
|
||||
return retScript
|
||||
}
|
||||
|
||||
// canonicalPush returns true if the object is either not a push instruction
|
||||
// or the push instruction contained wherein is matches the canonical form
|
||||
// or using the smallest instruction to do the job. False otherwise.
|
||||
func canonicalPush(pop parsedOpcode) bool {
|
||||
opcode := pop.opcode.value
|
||||
data := pop.data
|
||||
dataLen := len(pop.data)
|
||||
if opcode > OP_16 {
|
||||
return true
|
||||
}
|
||||
|
||||
if opcode < OP_PUSHDATA1 && opcode > OP_0 && (dataLen == 1 && data[0] <= 16) {
|
||||
return false
|
||||
}
|
||||
if opcode == OP_PUSHDATA1 && dataLen < OP_PUSHDATA1 {
|
||||
return false
|
||||
}
|
||||
if opcode == OP_PUSHDATA2 && dataLen <= 0xff {
|
||||
return false
|
||||
}
|
||||
if opcode == OP_PUSHDATA4 && dataLen <= 0xffff {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// removeOpcodeByData will return the script minus any opcodes that would push
|
||||
// the passed data to the stack.
|
||||
func removeOpcodeByData(pkscript []parsedOpcode, data []byte) []parsedOpcode {
|
||||
retScript := make([]parsedOpcode, 0, len(pkscript))
|
||||
for _, pop := range pkscript {
|
||||
if !canonicalPush(pop) || !bytes.Contains(pop.data, data) {
|
||||
retScript = append(retScript, pop)
|
||||
}
|
||||
}
|
||||
return retScript
|
||||
|
||||
}
|
||||
|
||||
// calcHashPrevOuts calculates a single hash of all the previous outputs
|
||||
// (txid:index) referenced within the passed transaction. This calculated hash
|
||||
// can be re-used when validating all inputs spending segwit outputs, with a
|
||||
// signature hash type of SigHashAll. This allows validation to re-use previous
|
||||
// hashing computation, reducing the complexity of validating SigHashAll inputs
|
||||
// from O(N^2) to O(N).
|
||||
func calcHashPrevOuts(tx *wire.MsgTx) chainhash.Hash {
|
||||
var b bytes.Buffer
|
||||
for _, in := range tx.TxIn {
|
||||
// First write out the 32-byte transaction ID one of whose
|
||||
// outputs are being referenced by this input.
|
||||
b.Write(in.PreviousOutPoint.Hash[:])
|
||||
|
||||
// Next, we'll encode the index of the referenced output as a
|
||||
// little endian integer.
|
||||
var buf [4]byte
|
||||
binary.LittleEndian.PutUint32(buf[:], in.PreviousOutPoint.Index)
|
||||
b.Write(buf[:])
|
||||
}
|
||||
|
||||
return chainhash.DoubleHashH(b.Bytes())
|
||||
}
|
||||
|
||||
// calcHashSequence computes an aggregated hash of each of the sequence numbers
|
||||
// within the inputs of the passed transaction. This single hash can be re-used
|
||||
// when validating all inputs spending segwit outputs, which include signatures
|
||||
// using the SigHashAll sighash type. This allows validation to re-use previous
|
||||
// hashing computation, reducing the complexity of validating SigHashAll inputs
|
||||
// from O(N^2) to O(N).
|
||||
func calcHashSequence(tx *wire.MsgTx) chainhash.Hash {
|
||||
var b bytes.Buffer
|
||||
for _, in := range tx.TxIn {
|
||||
var buf [4]byte
|
||||
binary.LittleEndian.PutUint32(buf[:], in.Sequence)
|
||||
b.Write(buf[:])
|
||||
}
|
||||
|
||||
return chainhash.DoubleHashH(b.Bytes())
|
||||
}
|
||||
|
||||
// calcHashOutputs computes a hash digest of all outputs created by the
|
||||
// transaction encoded using the wire format. This single hash can be re-used
|
||||
// when validating all inputs spending witness programs, which include
|
||||
// signatures using the SigHashAll sighash type. This allows computation to be
|
||||
// cached, reducing the total hashing complexity from O(N^2) to O(N).
|
||||
func calcHashOutputs(tx *wire.MsgTx) chainhash.Hash {
|
||||
var b bytes.Buffer
|
||||
for _, out := range tx.TxOut {
|
||||
wire.WriteTxOut(&b, 0, 0, out)
|
||||
}
|
||||
|
||||
return chainhash.DoubleHashH(b.Bytes())
|
||||
}
|
||||
|
||||
// calcWitnessSignatureHash computes the sighash digest of a transaction's
|
||||
// segwit input using the new, optimized digest calculation algorithm defined
|
||||
// in BIP0143: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki.
|
||||
// This function makes use of pre-calculated sighash fragments stored within
|
||||
// the passed HashCache to eliminate duplicate hashing computations when
|
||||
// calculating the final digest, reducing the complexity from O(N^2) to O(N).
|
||||
// Additionally, signatures now cover the input value of the referenced unspent
|
||||
// output. This allows offline, or hardware wallets to compute the exact amount
|
||||
// being spent, in addition to the final transaction fee. In the case the
|
||||
// wallet if fed an invalid input amount, the real sighash will differ causing
|
||||
// the produced signature to be invalid.
|
||||
func calcWitnessSignatureHash(subScript []parsedOpcode, sigHashes *TxSigHashes,
|
||||
hashType SigHashType, tx *wire.MsgTx, idx int, amt int64) ([]byte, error) {
|
||||
|
||||
// As a sanity check, ensure the passed input index for the transaction
|
||||
// is valid.
|
||||
if idx > len(tx.TxIn)-1 {
|
||||
return nil, fmt.Errorf("idx %d but %d txins", idx, len(tx.TxIn))
|
||||
}
|
||||
|
||||
// We'll utilize this buffer throughout to incrementally calculate
|
||||
// the signature hash for this transaction.
|
||||
var sigHash bytes.Buffer
|
||||
|
||||
// First write out, then encode the transaction's version number.
|
||||
var bVersion [4]byte
|
||||
binary.LittleEndian.PutUint32(bVersion[:], uint32(tx.Version))
|
||||
sigHash.Write(bVersion[:])
|
||||
|
||||
// Next write out the possibly pre-calculated hashes for the sequence
|
||||
// numbers of all inputs, and the hashes of the previous outs for all
|
||||
// outputs.
|
||||
var zeroHash chainhash.Hash
|
||||
|
||||
// If anyone can pay isn't active, then we can use the cached
|
||||
// hashPrevOuts, otherwise we just write zeroes for the prev outs.
|
||||
if hashType&SigHashAnyOneCanPay == 0 {
|
||||
sigHash.Write(sigHashes.HashPrevOuts[:])
|
||||
} else {
|
||||
sigHash.Write(zeroHash[:])
|
||||
}
|
||||
|
||||
// If the sighash isn't anyone can pay, single, or none, the use the
|
||||
// cached hash sequences, otherwise write all zeroes for the
|
||||
// hashSequence.
|
||||
if hashType&SigHashAnyOneCanPay == 0 &&
|
||||
hashType&sigHashMask != SigHashSingle &&
|
||||
hashType&sigHashMask != SigHashNone {
|
||||
sigHash.Write(sigHashes.HashSequence[:])
|
||||
} else {
|
||||
sigHash.Write(zeroHash[:])
|
||||
}
|
||||
|
||||
txIn := tx.TxIn[idx]
|
||||
|
||||
// Next, write the outpoint being spent.
|
||||
sigHash.Write(txIn.PreviousOutPoint.Hash[:])
|
||||
var bIndex [4]byte
|
||||
binary.LittleEndian.PutUint32(bIndex[:], txIn.PreviousOutPoint.Index)
|
||||
sigHash.Write(bIndex[:])
|
||||
|
||||
if isWitnessPubKeyHash(subScript) {
|
||||
// The script code for a p2wkh is a length prefix varint for
|
||||
// the next 25 bytes, followed by a re-creation of the original
|
||||
// p2pkh pk script.
|
||||
sigHash.Write([]byte{0x19})
|
||||
sigHash.Write([]byte{OP_DUP})
|
||||
sigHash.Write([]byte{OP_HASH160})
|
||||
sigHash.Write([]byte{OP_DATA_20})
|
||||
sigHash.Write(subScript[1].data)
|
||||
sigHash.Write([]byte{OP_EQUALVERIFY})
|
||||
sigHash.Write([]byte{OP_CHECKSIG})
|
||||
} else {
|
||||
// For p2wsh outputs, and future outputs, the script code is
|
||||
// the original script, with all code separators removed,
|
||||
// serialized with a var int length prefix.
|
||||
rawScript, _ := unparseScript(subScript)
|
||||
wire.WriteVarBytes(&sigHash, 0, rawScript)
|
||||
}
|
||||
|
||||
// Next, add the input amount, and sequence number of the input being
|
||||
// signed.
|
||||
var bAmount [8]byte
|
||||
binary.LittleEndian.PutUint64(bAmount[:], uint64(amt))
|
||||
sigHash.Write(bAmount[:])
|
||||
var bSequence [4]byte
|
||||
binary.LittleEndian.PutUint32(bSequence[:], txIn.Sequence)
|
||||
sigHash.Write(bSequence[:])
|
||||
|
||||
// If the current signature mode isn't single, or none, then we can
|
||||
// re-use the pre-generated hashoutputs sighash fragment. Otherwise,
|
||||
// we'll serialize and add only the target output index to the signature
|
||||
// pre-image.
|
||||
if hashType&SigHashSingle != SigHashSingle &&
|
||||
hashType&SigHashNone != SigHashNone {
|
||||
sigHash.Write(sigHashes.HashOutputs[:])
|
||||
} else if hashType&sigHashMask == SigHashSingle && idx < len(tx.TxOut) {
|
||||
var b bytes.Buffer
|
||||
wire.WriteTxOut(&b, 0, 0, tx.TxOut[idx])
|
||||
sigHash.Write(chainhash.DoubleHashB(b.Bytes()))
|
||||
} else {
|
||||
sigHash.Write(zeroHash[:])
|
||||
}
|
||||
|
||||
// Finally, write out the transaction's locktime, and the sig hash
|
||||
// type.
|
||||
var bLockTime [4]byte
|
||||
binary.LittleEndian.PutUint32(bLockTime[:], tx.LockTime)
|
||||
sigHash.Write(bLockTime[:])
|
||||
var bHashType [4]byte
|
||||
binary.LittleEndian.PutUint32(bHashType[:], uint32(hashType))
|
||||
sigHash.Write(bHashType[:])
|
||||
|
||||
return chainhash.DoubleHashB(sigHash.Bytes()), nil
|
||||
}
|
||||
|
||||
// CalcWitnessSigHash computes the sighash digest for the specified input of
|
||||
// the target transaction observing the desired sig hash type.
|
||||
func CalcWitnessSigHash(script []byte, sigHashes *TxSigHashes, hType SigHashType,
|
||||
tx *wire.MsgTx, idx int, amt int64) ([]byte, error) {
|
||||
|
||||
parsedScript, err := parseScript(script)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse output script: %v", err)
|
||||
}
|
||||
|
||||
return calcWitnessSignatureHash(parsedScript, sigHashes, hType, tx, idx,
|
||||
amt)
|
||||
}
|
||||
|
||||
// shallowCopyTx creates a shallow copy of the transaction for use when
|
||||
// calculating the signature hash. It is used over the Copy method on the
|
||||
// transaction itself since that is a deep copy and therefore does more work and
|
||||
// allocates much more space than needed.
|
||||
func shallowCopyTx(tx *wire.MsgTx) wire.MsgTx {
|
||||
// As an additional memory optimization, use contiguous backing arrays
|
||||
// for the copied inputs and outputs and point the final slice of
|
||||
// pointers into the contiguous arrays. This avoids a lot of small
|
||||
// allocations.
|
||||
txCopy := wire.MsgTx{
|
||||
Version: tx.Version,
|
||||
TxIn: make([]*wire.TxIn, len(tx.TxIn)),
|
||||
TxOut: make([]*wire.TxOut, len(tx.TxOut)),
|
||||
LockTime: tx.LockTime,
|
||||
}
|
||||
txIns := make([]wire.TxIn, len(tx.TxIn))
|
||||
for i, oldTxIn := range tx.TxIn {
|
||||
txIns[i] = *oldTxIn
|
||||
txCopy.TxIn[i] = &txIns[i]
|
||||
}
|
||||
txOuts := make([]wire.TxOut, len(tx.TxOut))
|
||||
for i, oldTxOut := range tx.TxOut {
|
||||
txOuts[i] = *oldTxOut
|
||||
txCopy.TxOut[i] = &txOuts[i]
|
||||
}
|
||||
return txCopy
|
||||
}
|
||||
|
||||
// CalcSignatureHash will, given a script and hash type for the current script
|
||||
// engine instance, calculate the signature hash to be used for signing and
|
||||
// verification.
|
||||
func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx int) ([]byte, error) {
|
||||
parsedScript, err := parseScript(script)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse output script: %v", err)
|
||||
}
|
||||
return calcSignatureHash(parsedScript, hashType, tx, idx), nil
|
||||
}
|
||||
|
||||
// calcSignatureHash will, given a script and hash type for the current script
|
||||
// engine instance, calculate the signature hash to be used for signing and
|
||||
// verification.
|
||||
func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) []byte {
|
||||
// The SigHashSingle signature type signs only the corresponding input
|
||||
// and output (the output with the same index number as the input).
|
||||
//
|
||||
// Since transactions can have more inputs than outputs, this means it
|
||||
// is improper to use SigHashSingle on input indices that don't have a
|
||||
// corresponding output.
|
||||
//
|
||||
// A bug in the original Satoshi client implementation means specifying
|
||||
// an index that is out of range results in a signature hash of 1 (as a
|
||||
// uint256 little endian). The original intent appeared to be to
|
||||
// indicate failure, but unfortunately, it was never checked and thus is
|
||||
// treated as the actual signature hash. This buggy behavior is now
|
||||
// part of the consensus and a hard fork would be required to fix it.
|
||||
//
|
||||
// Due to this, care must be taken by software that creates transactions
|
||||
// which make use of SigHashSingle because it can lead to an extremely
|
||||
// dangerous situation where the invalid inputs will end up signing a
|
||||
// hash of 1. This in turn presents an opportunity for attackers to
|
||||
// cleverly construct transactions which can steal those coins provided
|
||||
// they can reuse signatures.
|
||||
if hashType&sigHashMask == SigHashSingle && idx >= len(tx.TxOut) {
|
||||
var hash chainhash.Hash
|
||||
hash[0] = 0x01
|
||||
return hash[:]
|
||||
}
|
||||
|
||||
// Remove all instances of OP_CODESEPARATOR from the script.
|
||||
script = removeOpcode(script, OP_CODESEPARATOR)
|
||||
|
||||
// Make a shallow copy of the transaction, zeroing out the script for
|
||||
// all inputs that are not currently being processed.
|
||||
txCopy := shallowCopyTx(tx)
|
||||
for i := range txCopy.TxIn {
|
||||
if i == idx {
|
||||
// UnparseScript cannot fail here because removeOpcode
|
||||
// above only returns a valid script.
|
||||
sigScript, _ := unparseScript(script)
|
||||
txCopy.TxIn[idx].SignatureScript = sigScript
|
||||
} else {
|
||||
txCopy.TxIn[i].SignatureScript = nil
|
||||
}
|
||||
}
|
||||
|
||||
switch hashType & sigHashMask {
|
||||
case SigHashNone:
|
||||
txCopy.TxOut = txCopy.TxOut[0:0] // Empty slice.
|
||||
for i := range txCopy.TxIn {
|
||||
if i != idx {
|
||||
txCopy.TxIn[i].Sequence = 0
|
||||
}
|
||||
}
|
||||
|
||||
case SigHashSingle:
|
||||
// Resize output array to up to and including requested index.
|
||||
txCopy.TxOut = txCopy.TxOut[:idx+1]
|
||||
|
||||
// All but current output get zeroed out.
|
||||
for i := 0; i < idx; i++ {
|
||||
txCopy.TxOut[i].Value = -1
|
||||
txCopy.TxOut[i].PkScript = nil
|
||||
}
|
||||
|
||||
// Sequence on all other inputs is 0, too.
|
||||
for i := range txCopy.TxIn {
|
||||
if i != idx {
|
||||
txCopy.TxIn[i].Sequence = 0
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// Consensus treats undefined hashtypes like normal SigHashAll
|
||||
// for purposes of hash generation.
|
||||
fallthrough
|
||||
case SigHashOld:
|
||||
fallthrough
|
||||
case SigHashAll:
|
||||
// Nothing special here.
|
||||
}
|
||||
if hashType&SigHashAnyOneCanPay != 0 {
|
||||
txCopy.TxIn = txCopy.TxIn[idx : idx+1]
|
||||
}
|
||||
|
||||
// The final hash is the double sha256 of both the serialized modified
|
||||
// transaction and the hash type (encoded as a 4-byte little-endian
|
||||
// value) appended.
|
||||
wbuf := bytes.NewBuffer(make([]byte, 0, txCopy.SerializeSizeStripped()+4))
|
||||
txCopy.SerializeNoWitness(wbuf)
|
||||
binary.Write(wbuf, binary.LittleEndian, hashType)
|
||||
return chainhash.DoubleHashB(wbuf.Bytes())
|
||||
}
|
||||
|
||||
// asSmallInt returns the passed opcode, which must be true according to
|
||||
// isSmallInt(), as an integer.
|
||||
func asSmallInt(op *opcode) int {
|
||||
if op.value == OP_0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return int(op.value - (OP_1 - 1))
|
||||
}
|
||||
|
||||
// getSigOpCount is the implementation function for counting the number of
|
||||
// signature operations in the script provided by pops. If precise mode is
|
||||
// requested then we attempt to count the number of operations for a multisig
|
||||
// op. Otherwise we use the maximum.
|
||||
func getSigOpCount(pops []parsedOpcode, precise bool) int {
|
||||
nSigs := 0
|
||||
for i, pop := range pops {
|
||||
switch pop.opcode.value {
|
||||
case OP_CHECKSIG:
|
||||
fallthrough
|
||||
case OP_CHECKSIGVERIFY:
|
||||
nSigs++
|
||||
case OP_CHECKMULTISIG:
|
||||
fallthrough
|
||||
case OP_CHECKMULTISIGVERIFY:
|
||||
// If we are being precise then look for familiar
|
||||
// patterns for multisig, for now all we recognize is
|
||||
// OP_1 - OP_16 to signify the number of pubkeys.
|
||||
// Otherwise, we use the max of 20.
|
||||
if precise && i > 0 &&
|
||||
pops[i-1].opcode.value >= OP_1 &&
|
||||
pops[i-1].opcode.value <= OP_16 {
|
||||
nSigs += asSmallInt(pops[i-1].opcode)
|
||||
} else {
|
||||
nSigs += MaxPubKeysPerMultiSig
|
||||
}
|
||||
default:
|
||||
// Not a sigop.
|
||||
}
|
||||
}
|
||||
|
||||
return nSigs
|
||||
}
|
||||
|
||||
// GetSigOpCount provides a quick count of the number of signature operations
|
||||
// in a script. a CHECKSIG operations counts for 1, and a CHECK_MULTISIG for 20.
|
||||
// If the script fails to parse, then the count up to the point of failure is
|
||||
// returned.
|
||||
func GetSigOpCount(script []byte) int {
|
||||
// Don't check error since parseScript returns the parsed-up-to-error
|
||||
// list of pops.
|
||||
pops, _ := parseScript(script)
|
||||
return getSigOpCount(pops, false)
|
||||
}
|
||||
|
||||
// GetPreciseSigOpCount returns the number of signature operations in
|
||||
// scriptPubKey. If bip16 is true then scriptSig may be searched for the
|
||||
// Pay-To-Script-Hash script in order to find the precise number of signature
|
||||
// operations in the transaction. If the script fails to parse, then the count
|
||||
// up to the point of failure is returned.
|
||||
func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int {
|
||||
// Don't check error since parseScript returns the parsed-up-to-error
|
||||
// list of pops.
|
||||
pops, _ := parseScript(scriptPubKey)
|
||||
|
||||
// Treat non P2SH transactions as normal.
|
||||
if !(bip16 && isScriptHash(pops)) {
|
||||
return getSigOpCount(pops, true)
|
||||
}
|
||||
|
||||
// The public key script is a pay-to-script-hash, so parse the signature
|
||||
// script to get the final item. Scripts that fail to fully parse count
|
||||
// as 0 signature operations.
|
||||
sigPops, err := parseScript(scriptSig)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
// The signature script must only push data to the stack for P2SH to be
|
||||
// a valid pair, so the signature operation count is 0 when that is not
|
||||
// the case.
|
||||
if !isPushOnly(sigPops) || len(sigPops) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// The P2SH script is the last item the signature script pushes to the
|
||||
// stack. When the script is empty, there are no signature operations.
|
||||
shScript := sigPops[len(sigPops)-1].data
|
||||
if len(shScript) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Parse the P2SH script and don't check the error since parseScript
|
||||
// returns the parsed-up-to-error list of pops and the consensus rules
|
||||
// dictate signature operations are counted up to the first parse
|
||||
// failure.
|
||||
shPops, _ := parseScript(shScript)
|
||||
return getSigOpCount(shPops, true)
|
||||
}
|
||||
|
||||
// GetWitnessSigOpCount returns the number of signature operations generated by
|
||||
// spending the passed pkScript with the specified witness, or sigScript.
|
||||
// Unlike GetPreciseSigOpCount, this function is able to accurately count the
|
||||
// number of signature operations generated by spending witness programs, and
|
||||
// nested p2sh witness programs. If the script fails to parse, then the count
|
||||
// up to the point of failure is returned.
|
||||
func GetWitnessSigOpCount(sigScript, pkScript []byte, witness wire.TxWitness) int {
|
||||
// If this is a regular witness program, then we can proceed directly
|
||||
// to counting its signature operations without any further processing.
|
||||
if IsWitnessProgram(pkScript) {
|
||||
return getWitnessSigOps(pkScript, witness)
|
||||
}
|
||||
|
||||
// Next, we'll check the sigScript to see if this is a nested p2sh
|
||||
// witness program. This is a case wherein the sigScript is actually a
|
||||
// datapush of a p2wsh witness program.
|
||||
sigPops, err := parseScript(sigScript)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
if IsPayToScriptHash(pkScript) && isPushOnly(sigPops) &&
|
||||
IsWitnessProgram(sigScript[1:]) {
|
||||
return getWitnessSigOps(sigScript[1:], witness)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// getWitnessSigOps returns the number of signature operations generated by
|
||||
// spending the passed witness program wit the passed witness. The exact
|
||||
// signature counting heuristic is modified by the version of the passed
|
||||
// witness program. If the version of the witness program is unable to be
|
||||
// extracted, then 0 is returned for the sig op count.
|
||||
func getWitnessSigOps(pkScript []byte, witness wire.TxWitness) int {
|
||||
// Attempt to extract the witness program version.
|
||||
witnessVersion, witnessProgram, err := ExtractWitnessProgramInfo(
|
||||
pkScript,
|
||||
)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch witnessVersion {
|
||||
case 0:
|
||||
switch {
|
||||
case len(witnessProgram) == payToWitnessPubKeyHashDataSize:
|
||||
return 1
|
||||
case len(witnessProgram) == payToWitnessScriptHashDataSize &&
|
||||
len(witness) > 0:
|
||||
|
||||
witnessScript := witness[len(witness)-1]
|
||||
pops, _ := parseScript(witnessScript)
|
||||
return getSigOpCount(pops, true)
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// IsUnspendable returns whether the passed public key script is unspendable, or
|
||||
// guaranteed to fail at execution. This allows inputs to be pruned instantly
|
||||
// when entering the UTXO set.
|
||||
func IsUnspendable(pkScript []byte) bool {
|
||||
pops, err := parseScript(pkScript)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return len(pops) > 0 && pops[0].opcode.value == OP_RETURN
|
||||
}
|
||||
274
vendor/github.com/btcsuite/btcd/txscript/scriptbuilder.go
generated
vendored
Normal file
274
vendor/github.com/btcsuite/btcd/txscript/scriptbuilder.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
// Copyright (c) 2013-2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultScriptAlloc is the default size used for the backing array
|
||||
// for a script being built by the ScriptBuilder. The array will
|
||||
// dynamically grow as needed, but this figure is intended to provide
|
||||
// enough space for vast majority of scripts without needing to grow the
|
||||
// backing array multiple times.
|
||||
defaultScriptAlloc = 500
|
||||
)
|
||||
|
||||
// ErrScriptNotCanonical identifies a non-canonical script. The caller can use
|
||||
// a type assertion to detect this error type.
|
||||
type ErrScriptNotCanonical string
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e ErrScriptNotCanonical) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
// ScriptBuilder provides a facility for building custom scripts. It allows
|
||||
// you to push opcodes, ints, and data while respecting canonical encoding. In
|
||||
// general it does not ensure the script will execute correctly, however any
|
||||
// data pushes which would exceed the maximum allowed script engine limits and
|
||||
// are therefore guaranteed not to execute will not be pushed and will result in
|
||||
// the Script function returning an error.
|
||||
//
|
||||
// For example, the following would build a 2-of-3 multisig script for usage in
|
||||
// a pay-to-script-hash (although in this situation MultiSigScript() would be a
|
||||
// better choice to generate the script):
|
||||
// builder := txscript.NewScriptBuilder()
|
||||
// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
|
||||
// builder.AddData(pubKey3).AddOp(txscript.OP_3)
|
||||
// builder.AddOp(txscript.OP_CHECKMULTISIG)
|
||||
// script, err := builder.Script()
|
||||
// if err != nil {
|
||||
// // Handle the error.
|
||||
// return
|
||||
// }
|
||||
// fmt.Printf("Final multi-sig script: %x\n", script)
|
||||
type ScriptBuilder struct {
|
||||
script []byte
|
||||
err error
|
||||
}
|
||||
|
||||
// AddOp pushes the passed opcode to the end of the script. The script will not
|
||||
// be modified if pushing the opcode would cause the script to exceed the
|
||||
// maximum allowed script engine size.
|
||||
func (b *ScriptBuilder) AddOp(opcode byte) *ScriptBuilder {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
// Pushes that would cause the script to exceed the largest allowed
|
||||
// script size would result in a non-canonical script.
|
||||
if len(b.script)+1 > MaxScriptSize {
|
||||
str := fmt.Sprintf("adding an opcode would exceed the maximum "+
|
||||
"allowed canonical script length of %d", MaxScriptSize)
|
||||
b.err = ErrScriptNotCanonical(str)
|
||||
return b
|
||||
}
|
||||
|
||||
b.script = append(b.script, opcode)
|
||||
return b
|
||||
}
|
||||
|
||||
// AddOps pushes the passed opcodes to the end of the script. The script will
|
||||
// not be modified if pushing the opcodes would cause the script to exceed the
|
||||
// maximum allowed script engine size.
|
||||
func (b *ScriptBuilder) AddOps(opcodes []byte) *ScriptBuilder {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
// Pushes that would cause the script to exceed the largest allowed
|
||||
// script size would result in a non-canonical script.
|
||||
if len(b.script)+len(opcodes) > MaxScriptSize {
|
||||
str := fmt.Sprintf("adding opcodes would exceed the maximum "+
|
||||
"allowed canonical script length of %d", MaxScriptSize)
|
||||
b.err = ErrScriptNotCanonical(str)
|
||||
return b
|
||||
}
|
||||
|
||||
b.script = append(b.script, opcodes...)
|
||||
return b
|
||||
}
|
||||
|
||||
// canonicalDataSize returns the number of bytes the canonical encoding of the
|
||||
// data will take.
|
||||
func canonicalDataSize(data []byte) int {
|
||||
dataLen := len(data)
|
||||
|
||||
// When the data consists of a single number that can be represented
|
||||
// by one of the "small integer" opcodes, that opcode will be instead
|
||||
// of a data push opcode followed by the number.
|
||||
if dataLen == 0 {
|
||||
return 1
|
||||
} else if dataLen == 1 && data[0] <= 16 {
|
||||
return 1
|
||||
} else if dataLen == 1 && data[0] == 0x81 {
|
||||
return 1
|
||||
}
|
||||
|
||||
if dataLen < OP_PUSHDATA1 {
|
||||
return 1 + dataLen
|
||||
} else if dataLen <= 0xff {
|
||||
return 2 + dataLen
|
||||
} else if dataLen <= 0xffff {
|
||||
return 3 + dataLen
|
||||
}
|
||||
|
||||
return 5 + dataLen
|
||||
}
|
||||
|
||||
// addData is the internal function that actually pushes the passed data to the
|
||||
// end of the script. It automatically chooses canonical opcodes depending on
|
||||
// the length of the data. A zero length buffer will lead to a push of empty
|
||||
// data onto the stack (OP_0). No data limits are enforced with this function.
|
||||
func (b *ScriptBuilder) addData(data []byte) *ScriptBuilder {
|
||||
dataLen := len(data)
|
||||
|
||||
// When the data consists of a single number that can be represented
|
||||
// by one of the "small integer" opcodes, use that opcode instead of
|
||||
// a data push opcode followed by the number.
|
||||
if dataLen == 0 || dataLen == 1 && data[0] == 0 {
|
||||
b.script = append(b.script, OP_0)
|
||||
return b
|
||||
} else if dataLen == 1 && data[0] <= 16 {
|
||||
b.script = append(b.script, (OP_1-1)+data[0])
|
||||
return b
|
||||
} else if dataLen == 1 && data[0] == 0x81 {
|
||||
b.script = append(b.script, byte(OP_1NEGATE))
|
||||
return b
|
||||
}
|
||||
|
||||
// Use one of the OP_DATA_# opcodes if the length of the data is small
|
||||
// enough so the data push instruction is only a single byte.
|
||||
// Otherwise, choose the smallest possible OP_PUSHDATA# opcode that
|
||||
// can represent the length of the data.
|
||||
if dataLen < OP_PUSHDATA1 {
|
||||
b.script = append(b.script, byte((OP_DATA_1-1)+dataLen))
|
||||
} else if dataLen <= 0xff {
|
||||
b.script = append(b.script, OP_PUSHDATA1, byte(dataLen))
|
||||
} else if dataLen <= 0xffff {
|
||||
buf := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(buf, uint16(dataLen))
|
||||
b.script = append(b.script, OP_PUSHDATA2)
|
||||
b.script = append(b.script, buf...)
|
||||
} else {
|
||||
buf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(buf, uint32(dataLen))
|
||||
b.script = append(b.script, OP_PUSHDATA4)
|
||||
b.script = append(b.script, buf...)
|
||||
}
|
||||
|
||||
// Append the actual data.
|
||||
b.script = append(b.script, data...)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// AddFullData should not typically be used by ordinary users as it does not
|
||||
// include the checks which prevent data pushes larger than the maximum allowed
|
||||
// sizes which leads to scripts that can't be executed. This is provided for
|
||||
// testing purposes such as regression tests where sizes are intentionally made
|
||||
// larger than allowed.
|
||||
//
|
||||
// Use AddData instead.
|
||||
func (b *ScriptBuilder) AddFullData(data []byte) *ScriptBuilder {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
return b.addData(data)
|
||||
}
|
||||
|
||||
// AddData pushes the passed data to the end of the script. It automatically
|
||||
// chooses canonical opcodes depending on the length of the data. A zero length
|
||||
// buffer will lead to a push of empty data onto the stack (OP_0) and any push
|
||||
// of data greater than MaxScriptElementSize will not modify the script since
|
||||
// that is not allowed by the script engine. Also, the script will not be
|
||||
// modified if pushing the data would cause the script to exceed the maximum
|
||||
// allowed script engine size.
|
||||
func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
// Pushes that would cause the script to exceed the largest allowed
|
||||
// script size would result in a non-canonical script.
|
||||
dataSize := canonicalDataSize(data)
|
||||
if len(b.script)+dataSize > MaxScriptSize {
|
||||
str := fmt.Sprintf("adding %d bytes of data would exceed the "+
|
||||
"maximum allowed canonical script length of %d",
|
||||
dataSize, MaxScriptSize)
|
||||
b.err = ErrScriptNotCanonical(str)
|
||||
return b
|
||||
}
|
||||
|
||||
// Pushes larger than the max script element size would result in a
|
||||
// script that is not canonical.
|
||||
dataLen := len(data)
|
||||
if dataLen > MaxScriptElementSize {
|
||||
str := fmt.Sprintf("adding a data element of %d bytes would "+
|
||||
"exceed the maximum allowed script element size of %d",
|
||||
dataLen, MaxScriptElementSize)
|
||||
b.err = ErrScriptNotCanonical(str)
|
||||
return b
|
||||
}
|
||||
|
||||
return b.addData(data)
|
||||
}
|
||||
|
||||
// AddInt64 pushes the passed integer to the end of the script. The script will
|
||||
// not be modified if pushing the data would cause the script to exceed the
|
||||
// maximum allowed script engine size.
|
||||
func (b *ScriptBuilder) AddInt64(val int64) *ScriptBuilder {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
// Pushes that would cause the script to exceed the largest allowed
|
||||
// script size would result in a non-canonical script.
|
||||
if len(b.script)+1 > MaxScriptSize {
|
||||
str := fmt.Sprintf("adding an integer would exceed the "+
|
||||
"maximum allow canonical script length of %d",
|
||||
MaxScriptSize)
|
||||
b.err = ErrScriptNotCanonical(str)
|
||||
return b
|
||||
}
|
||||
|
||||
// Fast path for small integers and OP_1NEGATE.
|
||||
if val == 0 {
|
||||
b.script = append(b.script, OP_0)
|
||||
return b
|
||||
}
|
||||
if val == -1 || (val >= 1 && val <= 16) {
|
||||
b.script = append(b.script, byte((OP_1-1)+val))
|
||||
return b
|
||||
}
|
||||
|
||||
return b.AddData(scriptNum(val).Bytes())
|
||||
}
|
||||
|
||||
// Reset resets the script so it has no content.
|
||||
func (b *ScriptBuilder) Reset() *ScriptBuilder {
|
||||
b.script = b.script[0:0]
|
||||
b.err = nil
|
||||
return b
|
||||
}
|
||||
|
||||
// Script returns the currently built script. When any errors occurred while
|
||||
// building the script, the script will be returned up the point of the first
|
||||
// error along with the error.
|
||||
func (b *ScriptBuilder) Script() ([]byte, error) {
|
||||
return b.script, b.err
|
||||
}
|
||||
|
||||
// NewScriptBuilder returns a new instance of a script builder. See
|
||||
// ScriptBuilder for details.
|
||||
func NewScriptBuilder() *ScriptBuilder {
|
||||
return &ScriptBuilder{
|
||||
script: make([]byte, 0, defaultScriptAlloc),
|
||||
}
|
||||
}
|
||||
225
vendor/github.com/btcsuite/btcd/txscript/scriptnum.go
generated
vendored
Normal file
225
vendor/github.com/btcsuite/btcd/txscript/scriptnum.go
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
// Copyright (c) 2015-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
maxInt32 = 1<<31 - 1
|
||||
minInt32 = -1 << 31
|
||||
|
||||
// defaultScriptNumLen is the default number of bytes
|
||||
// data being interpreted as an integer may be.
|
||||
defaultScriptNumLen = 4
|
||||
)
|
||||
|
||||
// scriptNum represents a numeric value used in the scripting engine with
|
||||
// special handling to deal with the subtle semantics required by consensus.
|
||||
//
|
||||
// All numbers are stored on the data and alternate stacks encoded as little
|
||||
// endian with a sign bit. All numeric opcodes such as OP_ADD, OP_SUB,
|
||||
// and OP_MUL, are only allowed to operate on 4-byte integers in the range
|
||||
// [-2^31 + 1, 2^31 - 1], however the results of numeric operations may overflow
|
||||
// and remain valid so long as they are not used as inputs to other numeric
|
||||
// operations or otherwise interpreted as an integer.
|
||||
//
|
||||
// For example, it is possible for OP_ADD to have 2^31 - 1 for its two operands
|
||||
// resulting 2^32 - 2, which overflows, but is still pushed to the stack as the
|
||||
// result of the addition. That value can then be used as input to OP_VERIFY
|
||||
// which will succeed because the data is being interpreted as a boolean.
|
||||
// However, if that same value were to be used as input to another numeric
|
||||
// opcode, such as OP_SUB, it must fail.
|
||||
//
|
||||
// This type handles the aforementioned requirements by storing all numeric
|
||||
// operation results as an int64 to handle overflow and provides the Bytes
|
||||
// method to get the serialized representation (including values that overflow).
|
||||
//
|
||||
// Then, whenever data is interpreted as an integer, it is converted to this
|
||||
// type by using the makeScriptNum function which will return an error if the
|
||||
// number is out of range or not minimally encoded depending on parameters.
|
||||
// Since all numeric opcodes involve pulling data from the stack and
|
||||
// interpreting it as an integer, it provides the required behavior.
|
||||
type scriptNum int64
|
||||
|
||||
// checkMinimalDataEncoding returns whether or not the passed byte array adheres
|
||||
// to the minimal encoding requirements.
|
||||
func checkMinimalDataEncoding(v []byte) error {
|
||||
if len(v) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check that the number is encoded with the minimum possible
|
||||
// number of bytes.
|
||||
//
|
||||
// If the most-significant-byte - excluding the sign bit - is zero
|
||||
// then we're not minimal. Note how this test also rejects the
|
||||
// negative-zero encoding, [0x80].
|
||||
if v[len(v)-1]&0x7f == 0 {
|
||||
// One exception: if there's more than one byte and the most
|
||||
// significant bit of the second-most-significant-byte is set
|
||||
// it would conflict with the sign bit. An example of this case
|
||||
// is +-255, which encode to 0xff00 and 0xff80 respectively.
|
||||
// (big-endian).
|
||||
if len(v) == 1 || v[len(v)-2]&0x80 == 0 {
|
||||
str := fmt.Sprintf("numeric value encoded as %x is "+
|
||||
"not minimally encoded", v)
|
||||
return scriptError(ErrMinimalData, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes returns the number serialized as a little endian with a sign bit.
|
||||
//
|
||||
// Example encodings:
|
||||
// 127 -> [0x7f]
|
||||
// -127 -> [0xff]
|
||||
// 128 -> [0x80 0x00]
|
||||
// -128 -> [0x80 0x80]
|
||||
// 129 -> [0x81 0x00]
|
||||
// -129 -> [0x81 0x80]
|
||||
// 256 -> [0x00 0x01]
|
||||
// -256 -> [0x00 0x81]
|
||||
// 32767 -> [0xff 0x7f]
|
||||
// -32767 -> [0xff 0xff]
|
||||
// 32768 -> [0x00 0x80 0x00]
|
||||
// -32768 -> [0x00 0x80 0x80]
|
||||
func (n scriptNum) Bytes() []byte {
|
||||
// Zero encodes as an empty byte slice.
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Take the absolute value and keep track of whether it was originally
|
||||
// negative.
|
||||
isNegative := n < 0
|
||||
if isNegative {
|
||||
n = -n
|
||||
}
|
||||
|
||||
// Encode to little endian. The maximum number of encoded bytes is 9
|
||||
// (8 bytes for max int64 plus a potential byte for sign extension).
|
||||
result := make([]byte, 0, 9)
|
||||
for n > 0 {
|
||||
result = append(result, byte(n&0xff))
|
||||
n >>= 8
|
||||
}
|
||||
|
||||
// When the most significant byte already has the high bit set, an
|
||||
// additional high byte is required to indicate whether the number is
|
||||
// negative or positive. The additional byte is removed when converting
|
||||
// back to an integral and its high bit is used to denote the sign.
|
||||
//
|
||||
// Otherwise, when the most significant byte does not already have the
|
||||
// high bit set, use it to indicate the value is negative, if needed.
|
||||
if result[len(result)-1]&0x80 != 0 {
|
||||
extraByte := byte(0x00)
|
||||
if isNegative {
|
||||
extraByte = 0x80
|
||||
}
|
||||
result = append(result, extraByte)
|
||||
|
||||
} else if isNegative {
|
||||
result[len(result)-1] |= 0x80
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Int32 returns the script number clamped to a valid int32. That is to say
|
||||
// when the script number is higher than the max allowed int32, the max int32
|
||||
// value is returned and vice versa for the minimum value. Note that this
|
||||
// behavior is different from a simple int32 cast because that truncates
|
||||
// and the consensus rules dictate numbers which are directly cast to ints
|
||||
// provide this behavior.
|
||||
//
|
||||
// In practice, for most opcodes, the number should never be out of range since
|
||||
// it will have been created with makeScriptNum using the defaultScriptLen
|
||||
// value, which rejects them. In case something in the future ends up calling
|
||||
// this function against the result of some arithmetic, which IS allowed to be
|
||||
// out of range before being reinterpreted as an integer, this will provide the
|
||||
// correct behavior.
|
||||
func (n scriptNum) Int32() int32 {
|
||||
if n > maxInt32 {
|
||||
return maxInt32
|
||||
}
|
||||
|
||||
if n < minInt32 {
|
||||
return minInt32
|
||||
}
|
||||
|
||||
return int32(n)
|
||||
}
|
||||
|
||||
// makeScriptNum interprets the passed serialized bytes as an encoded integer
|
||||
// and returns the result as a script number.
|
||||
//
|
||||
// Since the consensus rules dictate that serialized bytes interpreted as ints
|
||||
// are only allowed to be in the range determined by a maximum number of bytes,
|
||||
// on a per opcode basis, an error will be returned when the provided bytes
|
||||
// would result in a number outside of that range. In particular, the range for
|
||||
// the vast majority of opcodes dealing with numeric values are limited to 4
|
||||
// bytes and therefore will pass that value to this function resulting in an
|
||||
// allowed range of [-2^31 + 1, 2^31 - 1].
|
||||
//
|
||||
// The requireMinimal flag causes an error to be returned if additional checks
|
||||
// on the encoding determine it is not represented with the smallest possible
|
||||
// number of bytes or is the negative 0 encoding, [0x80]. For example, consider
|
||||
// the number 127. It could be encoded as [0x7f], [0x7f 0x00],
|
||||
// [0x7f 0x00 0x00 ...], etc. All forms except [0x7f] will return an error with
|
||||
// requireMinimal enabled.
|
||||
//
|
||||
// The scriptNumLen is the maximum number of bytes the encoded value can be
|
||||
// before an ErrStackNumberTooBig is returned. This effectively limits the
|
||||
// range of allowed values.
|
||||
// WARNING: Great care should be taken if passing a value larger than
|
||||
// defaultScriptNumLen, which could lead to addition and multiplication
|
||||
// overflows.
|
||||
//
|
||||
// See the Bytes function documentation for example encodings.
|
||||
func makeScriptNum(v []byte, requireMinimal bool, scriptNumLen int) (scriptNum, error) {
|
||||
// Interpreting data requires that it is not larger than
|
||||
// the the passed scriptNumLen value.
|
||||
if len(v) > scriptNumLen {
|
||||
str := fmt.Sprintf("numeric value encoded as %x is %d bytes "+
|
||||
"which exceeds the max allowed of %d", v, len(v),
|
||||
scriptNumLen)
|
||||
return 0, scriptError(ErrNumberTooBig, str)
|
||||
}
|
||||
|
||||
// Enforce minimal encoded if requested.
|
||||
if requireMinimal {
|
||||
if err := checkMinimalDataEncoding(v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// Zero is encoded as an empty byte slice.
|
||||
if len(v) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Decode from little endian.
|
||||
var result int64
|
||||
for i, val := range v {
|
||||
result |= int64(val) << uint8(8*i)
|
||||
}
|
||||
|
||||
// When the most significant byte of the input bytes has the sign bit
|
||||
// set, the result is negative. So, remove the sign bit from the result
|
||||
// and make it negative.
|
||||
if v[len(v)-1]&0x80 != 0 {
|
||||
// The maximum length of v has already been determined to be 4
|
||||
// above, so uint8 is enough to cover the max possible shift
|
||||
// value of 24.
|
||||
result &= ^(int64(0x80) << uint8(8*(len(v)-1)))
|
||||
return scriptNum(-result), nil
|
||||
}
|
||||
|
||||
return scriptNum(result), nil
|
||||
}
|
||||
99
vendor/github.com/btcsuite/btcd/txscript/sigcache.go
generated
vendored
Normal file
99
vendor/github.com/btcsuite/btcd/txscript/sigcache.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2015-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
// sigCacheEntry represents an entry in the SigCache. Entries within the
|
||||
// SigCache are keyed according to the sigHash of the signature. In the
|
||||
// scenario of a cache-hit (according to the sigHash), an additional comparison
|
||||
// of the signature, and public key will be executed in order to ensure a complete
|
||||
// match. In the occasion that two sigHashes collide, the newer sigHash will
|
||||
// simply overwrite the existing entry.
|
||||
type sigCacheEntry struct {
|
||||
sig *btcec.Signature
|
||||
pubKey *btcec.PublicKey
|
||||
}
|
||||
|
||||
// SigCache implements an ECDSA signature verification cache with a randomized
|
||||
// entry eviction policy. Only valid signatures will be added to the cache. The
|
||||
// benefits of SigCache are two fold. Firstly, usage of SigCache mitigates a DoS
|
||||
// attack wherein an attack causes a victim's client to hang due to worst-case
|
||||
// behavior triggered while processing attacker crafted invalid transactions. A
|
||||
// detailed description of the mitigated DoS attack can be found here:
|
||||
// https://bitslog.wordpress.com/2013/01/23/fixed-bitcoin-vulnerability-explanation-why-the-signature-cache-is-a-dos-protection/.
|
||||
// Secondly, usage of the SigCache introduces a signature verification
|
||||
// optimization which speeds up the validation of transactions within a block,
|
||||
// if they've already been seen and verified within the mempool.
|
||||
type SigCache struct {
|
||||
sync.RWMutex
|
||||
validSigs map[chainhash.Hash]sigCacheEntry
|
||||
maxEntries uint
|
||||
}
|
||||
|
||||
// NewSigCache creates and initializes a new instance of SigCache. Its sole
|
||||
// parameter 'maxEntries' represents the maximum number of entries allowed to
|
||||
// exist in the SigCache at any particular moment. Random entries are evicted
|
||||
// to make room for new entries that would cause the number of entries in the
|
||||
// cache to exceed the max.
|
||||
func NewSigCache(maxEntries uint) *SigCache {
|
||||
return &SigCache{
|
||||
validSigs: make(map[chainhash.Hash]sigCacheEntry, maxEntries),
|
||||
maxEntries: maxEntries,
|
||||
}
|
||||
}
|
||||
|
||||
// Exists returns true if an existing entry of 'sig' over 'sigHash' for public
|
||||
// key 'pubKey' is found within the SigCache. Otherwise, false is returned.
|
||||
//
|
||||
// NOTE: This function is safe for concurrent access. Readers won't be blocked
|
||||
// unless there exists a writer, adding an entry to the SigCache.
|
||||
func (s *SigCache) Exists(sigHash chainhash.Hash, sig *btcec.Signature, pubKey *btcec.PublicKey) bool {
|
||||
s.RLock()
|
||||
entry, ok := s.validSigs[sigHash]
|
||||
s.RUnlock()
|
||||
|
||||
return ok && entry.pubKey.IsEqual(pubKey) && entry.sig.IsEqual(sig)
|
||||
}
|
||||
|
||||
// Add adds an entry for a signature over 'sigHash' under public key 'pubKey'
|
||||
// to the signature cache. In the event that the SigCache is 'full', an
|
||||
// existing entry is randomly chosen to be evicted in order to make space for
|
||||
// the new entry.
|
||||
//
|
||||
// NOTE: This function is safe for concurrent access. Writers will block
|
||||
// simultaneous readers until function execution has concluded.
|
||||
func (s *SigCache) Add(sigHash chainhash.Hash, sig *btcec.Signature, pubKey *btcec.PublicKey) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.maxEntries <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// If adding this new entry will put us over the max number of allowed
|
||||
// entries, then evict an entry.
|
||||
if uint(len(s.validSigs)+1) > s.maxEntries {
|
||||
// Remove a random entry from the map. Relying on the random
|
||||
// starting point of Go's map iteration. It's worth noting that
|
||||
// the random iteration starting point is not 100% guaranteed
|
||||
// by the spec, however most Go compilers support it.
|
||||
// Ultimately, the iteration order isn't important here because
|
||||
// in order to manipulate which items are evicted, an adversary
|
||||
// would need to be able to execute preimage attacks on the
|
||||
// hashing function in order to start eviction at a specific
|
||||
// entry.
|
||||
for sigEntry := range s.validSigs {
|
||||
delete(s.validSigs, sigEntry)
|
||||
break
|
||||
}
|
||||
}
|
||||
s.validSigs[sigHash] = sigCacheEntry{sig, pubKey}
|
||||
}
|
||||
464
vendor/github.com/btcsuite/btcd/txscript/sign.go
generated
vendored
Normal file
464
vendor/github.com/btcsuite/btcd/txscript/sign.go
generated
vendored
Normal file
@@ -0,0 +1,464 @@
|
||||
// Copyright (c) 2013-2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// RawTxInWitnessSignature returns the serialized ECDA signature for the input
|
||||
// idx of the given transaction, with the hashType appended to it. This
|
||||
// function is identical to RawTxInSignature, however the signature generated
|
||||
// signs a new sighash digest defined in BIP0143.
|
||||
func RawTxInWitnessSignature(tx *wire.MsgTx, sigHashes *TxSigHashes, idx int,
|
||||
amt int64, subScript []byte, hashType SigHashType,
|
||||
key *btcec.PrivateKey) ([]byte, error) {
|
||||
|
||||
parsedScript, err := parseScript(subScript)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse output script: %v", err)
|
||||
}
|
||||
|
||||
hash, err := calcWitnessSignatureHash(parsedScript, sigHashes, hashType, tx,
|
||||
idx, amt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signature, err := key.Sign(hash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot sign tx input: %s", err)
|
||||
}
|
||||
|
||||
return append(signature.Serialize(), byte(hashType)), nil
|
||||
}
|
||||
|
||||
// WitnessSignature creates an input witness stack for tx to spend BTC sent
|
||||
// from a previous output to the owner of privKey using the p2wkh script
|
||||
// template. The passed transaction must contain all the inputs and outputs as
|
||||
// dictated by the passed hashType. The signature generated observes the new
|
||||
// transaction digest algorithm defined within BIP0143.
|
||||
func WitnessSignature(tx *wire.MsgTx, sigHashes *TxSigHashes, idx int, amt int64,
|
||||
subscript []byte, hashType SigHashType, privKey *btcec.PrivateKey,
|
||||
compress bool) (wire.TxWitness, error) {
|
||||
|
||||
sig, err := RawTxInWitnessSignature(tx, sigHashes, idx, amt, subscript,
|
||||
hashType, privKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk := (*btcec.PublicKey)(&privKey.PublicKey)
|
||||
var pkData []byte
|
||||
if compress {
|
||||
pkData = pk.SerializeCompressed()
|
||||
} else {
|
||||
pkData = pk.SerializeUncompressed()
|
||||
}
|
||||
|
||||
// A witness script is actually a stack, so we return an array of byte
|
||||
// slices here, rather than a single byte slice.
|
||||
return wire.TxWitness{sig, pkData}, nil
|
||||
}
|
||||
|
||||
// RawTxInSignature returns the serialized ECDSA signature for the input idx of
|
||||
// the given transaction, with hashType appended to it.
|
||||
func RawTxInSignature(tx *wire.MsgTx, idx int, subScript []byte,
|
||||
hashType SigHashType, key *btcec.PrivateKey) ([]byte, error) {
|
||||
|
||||
hash, err := CalcSignatureHash(subScript, hashType, tx, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature, err := key.Sign(hash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot sign tx input: %s", err)
|
||||
}
|
||||
|
||||
return append(signature.Serialize(), byte(hashType)), nil
|
||||
}
|
||||
|
||||
// SignatureScript creates an input signature script for tx to spend BTC sent
|
||||
// from a previous output to the owner of privKey. tx must include all
|
||||
// transaction inputs and outputs, however txin scripts are allowed to be filled
|
||||
// or empty. The returned script is calculated to be used as the idx'th txin
|
||||
// sigscript for tx. subscript is the PkScript of the previous output being used
|
||||
// as the idx'th input. privKey is serialized in either a compressed or
|
||||
// uncompressed format based on compress. This format must match the same format
|
||||
// used to generate the payment address, or the script validation will fail.
|
||||
func SignatureScript(tx *wire.MsgTx, idx int, subscript []byte, hashType SigHashType, privKey *btcec.PrivateKey, compress bool) ([]byte, error) {
|
||||
sig, err := RawTxInSignature(tx, idx, subscript, hashType, privKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk := (*btcec.PublicKey)(&privKey.PublicKey)
|
||||
var pkData []byte
|
||||
if compress {
|
||||
pkData = pk.SerializeCompressed()
|
||||
} else {
|
||||
pkData = pk.SerializeUncompressed()
|
||||
}
|
||||
|
||||
return NewScriptBuilder().AddData(sig).AddData(pkData).Script()
|
||||
}
|
||||
|
||||
func p2pkSignatureScript(tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType, privKey *btcec.PrivateKey) ([]byte, error) {
|
||||
sig, err := RawTxInSignature(tx, idx, subScript, hashType, privKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewScriptBuilder().AddData(sig).Script()
|
||||
}
|
||||
|
||||
// signMultiSig signs as many of the outputs in the provided multisig script as
|
||||
// possible. It returns the generated script and a boolean if the script fulfils
|
||||
// the contract (i.e. nrequired signatures are provided). Since it is arguably
|
||||
// legal to not be able to sign any of the outputs, no error is returned.
|
||||
func signMultiSig(tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType,
|
||||
addresses []btcutil.Address, nRequired int, kdb KeyDB) ([]byte, bool) {
|
||||
// We start with a single OP_FALSE to work around the (now standard)
|
||||
// but in the reference implementation that causes a spurious pop at
|
||||
// the end of OP_CHECKMULTISIG.
|
||||
builder := NewScriptBuilder().AddOp(OP_FALSE)
|
||||
signed := 0
|
||||
for _, addr := range addresses {
|
||||
key, _, err := kdb.GetKey(addr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
sig, err := RawTxInSignature(tx, idx, subScript, hashType, key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
builder.AddData(sig)
|
||||
signed++
|
||||
if signed == nRequired {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
script, _ := builder.Script()
|
||||
return script, signed == nRequired
|
||||
}
|
||||
|
||||
func sign(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
subScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB) ([]byte,
|
||||
ScriptClass, []btcutil.Address, int, error) {
|
||||
|
||||
class, addresses, nrequired, err := ExtractPkScriptAddrs(subScript,
|
||||
chainParams)
|
||||
if err != nil {
|
||||
return nil, NonStandardTy, nil, 0, err
|
||||
}
|
||||
|
||||
switch class {
|
||||
case PubKeyTy:
|
||||
// look up key for address
|
||||
key, _, err := kdb.GetKey(addresses[0])
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
}
|
||||
|
||||
script, err := p2pkSignatureScript(tx, idx, subScript, hashType,
|
||||
key)
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
}
|
||||
|
||||
return script, class, addresses, nrequired, nil
|
||||
case PubKeyHashTy:
|
||||
// look up key for address
|
||||
key, compressed, err := kdb.GetKey(addresses[0])
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
}
|
||||
|
||||
script, err := SignatureScript(tx, idx, subScript, hashType,
|
||||
key, compressed)
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
}
|
||||
|
||||
return script, class, addresses, nrequired, nil
|
||||
case ScriptHashTy:
|
||||
script, err := sdb.GetScript(addresses[0])
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
}
|
||||
|
||||
return script, class, addresses, nrequired, nil
|
||||
case MultiSigTy:
|
||||
script, _ := signMultiSig(tx, idx, subScript, hashType,
|
||||
addresses, nrequired, kdb)
|
||||
return script, class, addresses, nrequired, nil
|
||||
case NullDataTy:
|
||||
return nil, class, nil, 0,
|
||||
errors.New("can't sign NULLDATA transactions")
|
||||
default:
|
||||
return nil, class, nil, 0,
|
||||
errors.New("can't sign unknown transactions")
|
||||
}
|
||||
}
|
||||
|
||||
// mergeScripts merges sigScript and prevScript assuming they are both
|
||||
// partial solutions for pkScript spending output idx of tx. class, addresses
|
||||
// and nrequired are the result of extracting the addresses from pkscript.
|
||||
// The return value is the best effort merging of the two scripts. Calling this
|
||||
// function with addresses, class and nrequired that do not match pkScript is
|
||||
// an error and results in undefined behaviour.
|
||||
func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
pkScript []byte, class ScriptClass, addresses []btcutil.Address,
|
||||
nRequired int, sigScript, prevScript []byte) []byte {
|
||||
|
||||
// TODO: the scripthash and multisig paths here are overly
|
||||
// inefficient in that they will recompute already known data.
|
||||
// some internal refactoring could probably make this avoid needless
|
||||
// extra calculations.
|
||||
switch class {
|
||||
case ScriptHashTy:
|
||||
// Remove the last push in the script and then recurse.
|
||||
// this could be a lot less inefficient.
|
||||
sigPops, err := parseScript(sigScript)
|
||||
if err != nil || len(sigPops) == 0 {
|
||||
return prevScript
|
||||
}
|
||||
prevPops, err := parseScript(prevScript)
|
||||
if err != nil || len(prevPops) == 0 {
|
||||
return sigScript
|
||||
}
|
||||
|
||||
// assume that script in sigPops is the correct one, we just
|
||||
// made it.
|
||||
script := sigPops[len(sigPops)-1].data
|
||||
|
||||
// We already know this information somewhere up the stack.
|
||||
class, addresses, nrequired, _ :=
|
||||
ExtractPkScriptAddrs(script, chainParams)
|
||||
|
||||
// regenerate scripts.
|
||||
sigScript, _ := unparseScript(sigPops)
|
||||
prevScript, _ := unparseScript(prevPops)
|
||||
|
||||
// Merge
|
||||
mergedScript := mergeScripts(chainParams, tx, idx, script,
|
||||
class, addresses, nrequired, sigScript, prevScript)
|
||||
|
||||
// Reappend the script and return the result.
|
||||
builder := NewScriptBuilder()
|
||||
builder.AddOps(mergedScript)
|
||||
builder.AddData(script)
|
||||
finalScript, _ := builder.Script()
|
||||
return finalScript
|
||||
case MultiSigTy:
|
||||
return mergeMultiSig(tx, idx, addresses, nRequired, pkScript,
|
||||
sigScript, prevScript)
|
||||
|
||||
// It doesn't actually make sense to merge anything other than multiig
|
||||
// and scripthash (because it could contain multisig). Everything else
|
||||
// has either zero signature, can't be spent, or has a single signature
|
||||
// which is either present or not. The other two cases are handled
|
||||
// above. In the conflict case here we just assume the longest is
|
||||
// correct (this matches behaviour of the reference implementation).
|
||||
default:
|
||||
if len(sigScript) > len(prevScript) {
|
||||
return sigScript
|
||||
}
|
||||
return prevScript
|
||||
}
|
||||
}
|
||||
|
||||
// mergeMultiSig combines the two signature scripts sigScript and prevScript
|
||||
// that both provide signatures for pkScript in output idx of tx. addresses
|
||||
// and nRequired should be the results from extracting the addresses from
|
||||
// pkScript. Since this function is internal only we assume that the arguments
|
||||
// have come from other functions internally and thus are all consistent with
|
||||
// each other, behaviour is undefined if this contract is broken.
|
||||
func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []btcutil.Address,
|
||||
nRequired int, pkScript, sigScript, prevScript []byte) []byte {
|
||||
|
||||
// This is an internal only function and we already parsed this script
|
||||
// as ok for multisig (this is how we got here), so if this fails then
|
||||
// all assumptions are broken and who knows which way is up?
|
||||
pkPops, _ := parseScript(pkScript)
|
||||
|
||||
sigPops, err := parseScript(sigScript)
|
||||
if err != nil || len(sigPops) == 0 {
|
||||
return prevScript
|
||||
}
|
||||
|
||||
prevPops, err := parseScript(prevScript)
|
||||
if err != nil || len(prevPops) == 0 {
|
||||
return sigScript
|
||||
}
|
||||
|
||||
// Convenience function to avoid duplication.
|
||||
extractSigs := func(pops []parsedOpcode, sigs [][]byte) [][]byte {
|
||||
for _, pop := range pops {
|
||||
if len(pop.data) != 0 {
|
||||
sigs = append(sigs, pop.data)
|
||||
}
|
||||
}
|
||||
return sigs
|
||||
}
|
||||
|
||||
possibleSigs := make([][]byte, 0, len(sigPops)+len(prevPops))
|
||||
possibleSigs = extractSigs(sigPops, possibleSigs)
|
||||
possibleSigs = extractSigs(prevPops, possibleSigs)
|
||||
|
||||
// Now we need to match the signatures to pubkeys, the only real way to
|
||||
// do that is to try to verify them all and match it to the pubkey
|
||||
// that verifies it. we then can go through the addresses in order
|
||||
// to build our script. Anything that doesn't parse or doesn't verify we
|
||||
// throw away.
|
||||
addrToSig := make(map[string][]byte)
|
||||
sigLoop:
|
||||
for _, sig := range possibleSigs {
|
||||
|
||||
// can't have a valid signature that doesn't at least have a
|
||||
// hashtype, in practise it is even longer than this. but
|
||||
// that'll be checked next.
|
||||
if len(sig) < 1 {
|
||||
continue
|
||||
}
|
||||
tSig := sig[:len(sig)-1]
|
||||
hashType := SigHashType(sig[len(sig)-1])
|
||||
|
||||
pSig, err := btcec.ParseDERSignature(tSig, btcec.S256())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// We have to do this each round since hash types may vary
|
||||
// between signatures and so the hash will vary. We can,
|
||||
// however, assume no sigs etc are in the script since that
|
||||
// would make the transaction nonstandard and thus not
|
||||
// MultiSigTy, so we just need to hash the full thing.
|
||||
hash := calcSignatureHash(pkPops, hashType, tx, idx)
|
||||
|
||||
for _, addr := range addresses {
|
||||
// All multisig addresses should be pubkey addresses
|
||||
// it is an error to call this internal function with
|
||||
// bad input.
|
||||
pkaddr := addr.(*btcutil.AddressPubKey)
|
||||
|
||||
pubKey := pkaddr.PubKey()
|
||||
|
||||
// If it matches we put it in the map. We only
|
||||
// can take one signature per public key so if we
|
||||
// already have one, we can throw this away.
|
||||
if pSig.Verify(hash, pubKey) {
|
||||
aStr := addr.EncodeAddress()
|
||||
if _, ok := addrToSig[aStr]; !ok {
|
||||
addrToSig[aStr] = sig
|
||||
}
|
||||
continue sigLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extra opcode to handle the extra arg consumed (due to previous bugs
|
||||
// in the reference implementation).
|
||||
builder := NewScriptBuilder().AddOp(OP_FALSE)
|
||||
doneSigs := 0
|
||||
// This assumes that addresses are in the same order as in the script.
|
||||
for _, addr := range addresses {
|
||||
sig, ok := addrToSig[addr.EncodeAddress()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
builder.AddData(sig)
|
||||
doneSigs++
|
||||
if doneSigs == nRequired {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// padding for missing ones.
|
||||
for i := doneSigs; i < nRequired; i++ {
|
||||
builder.AddOp(OP_0)
|
||||
}
|
||||
|
||||
script, _ := builder.Script()
|
||||
return script
|
||||
}
|
||||
|
||||
// KeyDB is an interface type provided to SignTxOutput, it encapsulates
|
||||
// any user state required to get the private keys for an address.
|
||||
type KeyDB interface {
|
||||
GetKey(btcutil.Address) (*btcec.PrivateKey, bool, error)
|
||||
}
|
||||
|
||||
// KeyClosure implements KeyDB with a closure.
|
||||
type KeyClosure func(btcutil.Address) (*btcec.PrivateKey, bool, error)
|
||||
|
||||
// GetKey implements KeyDB by returning the result of calling the closure.
|
||||
func (kc KeyClosure) GetKey(address btcutil.Address) (*btcec.PrivateKey,
|
||||
bool, error) {
|
||||
return kc(address)
|
||||
}
|
||||
|
||||
// ScriptDB is an interface type provided to SignTxOutput, it encapsulates any
|
||||
// user state required to get the scripts for an pay-to-script-hash address.
|
||||
type ScriptDB interface {
|
||||
GetScript(btcutil.Address) ([]byte, error)
|
||||
}
|
||||
|
||||
// ScriptClosure implements ScriptDB with a closure.
|
||||
type ScriptClosure func(btcutil.Address) ([]byte, error)
|
||||
|
||||
// GetScript implements ScriptDB by returning the result of calling the closure.
|
||||
func (sc ScriptClosure) GetScript(address btcutil.Address) ([]byte, error) {
|
||||
return sc(address)
|
||||
}
|
||||
|
||||
// SignTxOutput signs output idx of the given tx to resolve the script given in
|
||||
// pkScript with a signature type of hashType. Any keys required will be
|
||||
// looked up by calling getKey() with the string of the given address.
|
||||
// Any pay-to-script-hash signatures will be similarly looked up by calling
|
||||
// getScript. If previousScript is provided then the results in previousScript
|
||||
// will be merged in a type-dependent manner with the newly generated.
|
||||
// signature script.
|
||||
func SignTxOutput(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
pkScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB,
|
||||
previousScript []byte) ([]byte, error) {
|
||||
|
||||
sigScript, class, addresses, nrequired, err := sign(chainParams, tx,
|
||||
idx, pkScript, hashType, kdb, sdb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if class == ScriptHashTy {
|
||||
// TODO keep the sub addressed and pass down to merge.
|
||||
realSigScript, _, _, _, err := sign(chainParams, tx, idx,
|
||||
sigScript, hashType, kdb, sdb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Append the p2sh script as the last push in the script.
|
||||
builder := NewScriptBuilder()
|
||||
builder.AddOps(realSigScript)
|
||||
builder.AddData(sigScript)
|
||||
|
||||
sigScript, _ = builder.Script()
|
||||
// TODO keep a copy of the script for merging.
|
||||
}
|
||||
|
||||
// Merge scripts. with any previous data, if any.
|
||||
mergedScript := mergeScripts(chainParams, tx, idx, pkScript, class,
|
||||
addresses, nrequired, sigScript, previousScript)
|
||||
return mergedScript, nil
|
||||
}
|
||||
361
vendor/github.com/btcsuite/btcd/txscript/stack.go
generated
vendored
Normal file
361
vendor/github.com/btcsuite/btcd/txscript/stack.go
generated
vendored
Normal file
@@ -0,0 +1,361 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// asBool gets the boolean value of the byte array.
|
||||
func asBool(t []byte) bool {
|
||||
for i := range t {
|
||||
if t[i] != 0 {
|
||||
// Negative 0 is also considered false.
|
||||
if i == len(t)-1 && t[i] == 0x80 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// fromBool converts a boolean into the appropriate byte array.
|
||||
func fromBool(v bool) []byte {
|
||||
if v {
|
||||
return []byte{1}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// stack represents a stack of immutable objects to be used with bitcoin
|
||||
// scripts. Objects may be shared, therefore in usage if a value is to be
|
||||
// changed it *must* be deep-copied first to avoid changing other values on the
|
||||
// stack.
|
||||
type stack struct {
|
||||
stk [][]byte
|
||||
verifyMinimalData bool
|
||||
}
|
||||
|
||||
// Depth returns the number of items on the stack.
|
||||
func (s *stack) Depth() int32 {
|
||||
return int32(len(s.stk))
|
||||
}
|
||||
|
||||
// PushByteArray adds the given back array to the top of the stack.
|
||||
//
|
||||
// Stack transformation: [... x1 x2] -> [... x1 x2 data]
|
||||
func (s *stack) PushByteArray(so []byte) {
|
||||
s.stk = append(s.stk, so)
|
||||
}
|
||||
|
||||
// PushInt converts the provided scriptNum to a suitable byte array then pushes
|
||||
// it onto the top of the stack.
|
||||
//
|
||||
// Stack transformation: [... x1 x2] -> [... x1 x2 int]
|
||||
func (s *stack) PushInt(val scriptNum) {
|
||||
s.PushByteArray(val.Bytes())
|
||||
}
|
||||
|
||||
// PushBool converts the provided boolean to a suitable byte array then pushes
|
||||
// it onto the top of the stack.
|
||||
//
|
||||
// Stack transformation: [... x1 x2] -> [... x1 x2 bool]
|
||||
func (s *stack) PushBool(val bool) {
|
||||
s.PushByteArray(fromBool(val))
|
||||
}
|
||||
|
||||
// PopByteArray pops the value off the top of the stack and returns it.
|
||||
//
|
||||
// Stack transformation: [... x1 x2 x3] -> [... x1 x2]
|
||||
func (s *stack) PopByteArray() ([]byte, error) {
|
||||
return s.nipN(0)
|
||||
}
|
||||
|
||||
// PopInt pops the value off the top of the stack, converts it into a script
|
||||
// num, and returns it. The act of converting to a script num enforces the
|
||||
// consensus rules imposed on data interpreted as numbers.
|
||||
//
|
||||
// Stack transformation: [... x1 x2 x3] -> [... x1 x2]
|
||||
func (s *stack) PopInt() (scriptNum, error) {
|
||||
so, err := s.PopByteArray()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
|
||||
}
|
||||
|
||||
// PopBool pops the value off the top of the stack, converts it into a bool, and
|
||||
// returns it.
|
||||
//
|
||||
// Stack transformation: [... x1 x2 x3] -> [... x1 x2]
|
||||
func (s *stack) PopBool() (bool, error) {
|
||||
so, err := s.PopByteArray()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return asBool(so), nil
|
||||
}
|
||||
|
||||
// PeekByteArray returns the Nth item on the stack without removing it.
|
||||
func (s *stack) PeekByteArray(idx int32) ([]byte, error) {
|
||||
sz := int32(len(s.stk))
|
||||
if idx < 0 || idx >= sz {
|
||||
str := fmt.Sprintf("index %d is invalid for stack size %d", idx,
|
||||
sz)
|
||||
return nil, scriptError(ErrInvalidStackOperation, str)
|
||||
}
|
||||
|
||||
return s.stk[sz-idx-1], nil
|
||||
}
|
||||
|
||||
// PeekInt returns the Nth item on the stack as a script num without removing
|
||||
// it. The act of converting to a script num enforces the consensus rules
|
||||
// imposed on data interpreted as numbers.
|
||||
func (s *stack) PeekInt(idx int32) (scriptNum, error) {
|
||||
so, err := s.PeekByteArray(idx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
|
||||
}
|
||||
|
||||
// PeekBool returns the Nth item on the stack as a bool without removing it.
|
||||
func (s *stack) PeekBool(idx int32) (bool, error) {
|
||||
so, err := s.PeekByteArray(idx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return asBool(so), nil
|
||||
}
|
||||
|
||||
// nipN is an internal function that removes the nth item on the stack and
|
||||
// returns it.
|
||||
//
|
||||
// Stack transformation:
|
||||
// nipN(0): [... x1 x2 x3] -> [... x1 x2]
|
||||
// nipN(1): [... x1 x2 x3] -> [... x1 x3]
|
||||
// nipN(2): [... x1 x2 x3] -> [... x2 x3]
|
||||
func (s *stack) nipN(idx int32) ([]byte, error) {
|
||||
sz := int32(len(s.stk))
|
||||
if idx < 0 || idx > sz-1 {
|
||||
str := fmt.Sprintf("index %d is invalid for stack size %d", idx,
|
||||
sz)
|
||||
return nil, scriptError(ErrInvalidStackOperation, str)
|
||||
}
|
||||
|
||||
so := s.stk[sz-idx-1]
|
||||
if idx == 0 {
|
||||
s.stk = s.stk[:sz-1]
|
||||
} else if idx == sz-1 {
|
||||
s1 := make([][]byte, sz-1)
|
||||
copy(s1, s.stk[1:])
|
||||
s.stk = s1
|
||||
} else {
|
||||
s1 := s.stk[sz-idx : sz]
|
||||
s.stk = s.stk[:sz-idx-1]
|
||||
s.stk = append(s.stk, s1...)
|
||||
}
|
||||
return so, nil
|
||||
}
|
||||
|
||||
// NipN removes the Nth object on the stack
|
||||
//
|
||||
// Stack transformation:
|
||||
// NipN(0): [... x1 x2 x3] -> [... x1 x2]
|
||||
// NipN(1): [... x1 x2 x3] -> [... x1 x3]
|
||||
// NipN(2): [... x1 x2 x3] -> [... x2 x3]
|
||||
func (s *stack) NipN(idx int32) error {
|
||||
_, err := s.nipN(idx)
|
||||
return err
|
||||
}
|
||||
|
||||
// Tuck copies the item at the top of the stack and inserts it before the 2nd
|
||||
// to top item.
|
||||
//
|
||||
// Stack transformation: [... x1 x2] -> [... x2 x1 x2]
|
||||
func (s *stack) Tuck() error {
|
||||
so2, err := s.PopByteArray()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
so1, err := s.PopByteArray()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.PushByteArray(so2) // stack [... x2]
|
||||
s.PushByteArray(so1) // stack [... x2 x1]
|
||||
s.PushByteArray(so2) // stack [... x2 x1 x2]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DropN removes the top N items from the stack.
|
||||
//
|
||||
// Stack transformation:
|
||||
// DropN(1): [... x1 x2] -> [... x1]
|
||||
// DropN(2): [... x1 x2] -> [...]
|
||||
func (s *stack) DropN(n int32) error {
|
||||
if n < 1 {
|
||||
str := fmt.Sprintf("attempt to drop %d items from stack", n)
|
||||
return scriptError(ErrInvalidStackOperation, str)
|
||||
}
|
||||
|
||||
for ; n > 0; n-- {
|
||||
_, err := s.PopByteArray()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DupN duplicates the top N items on the stack.
|
||||
//
|
||||
// Stack transformation:
|
||||
// DupN(1): [... x1 x2] -> [... x1 x2 x2]
|
||||
// DupN(2): [... x1 x2] -> [... x1 x2 x1 x2]
|
||||
func (s *stack) DupN(n int32) error {
|
||||
if n < 1 {
|
||||
str := fmt.Sprintf("attempt to dup %d stack items", n)
|
||||
return scriptError(ErrInvalidStackOperation, str)
|
||||
}
|
||||
|
||||
// Iteratively duplicate the value n-1 down the stack n times.
|
||||
// This leaves an in-order duplicate of the top n items on the stack.
|
||||
for i := n; i > 0; i-- {
|
||||
so, err := s.PeekByteArray(n - 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.PushByteArray(so)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RotN rotates the top 3N items on the stack to the left N times.
|
||||
//
|
||||
// Stack transformation:
|
||||
// RotN(1): [... x1 x2 x3] -> [... x2 x3 x1]
|
||||
// RotN(2): [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2]
|
||||
func (s *stack) RotN(n int32) error {
|
||||
if n < 1 {
|
||||
str := fmt.Sprintf("attempt to rotate %d stack items", n)
|
||||
return scriptError(ErrInvalidStackOperation, str)
|
||||
}
|
||||
|
||||
// Nip the 3n-1th item from the stack to the top n times to rotate
|
||||
// them up to the head of the stack.
|
||||
entry := 3*n - 1
|
||||
for i := n; i > 0; i-- {
|
||||
so, err := s.nipN(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.PushByteArray(so)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SwapN swaps the top N items on the stack with those below them.
|
||||
//
|
||||
// Stack transformation:
|
||||
// SwapN(1): [... x1 x2] -> [... x2 x1]
|
||||
// SwapN(2): [... x1 x2 x3 x4] -> [... x3 x4 x1 x2]
|
||||
func (s *stack) SwapN(n int32) error {
|
||||
if n < 1 {
|
||||
str := fmt.Sprintf("attempt to swap %d stack items", n)
|
||||
return scriptError(ErrInvalidStackOperation, str)
|
||||
}
|
||||
|
||||
entry := 2*n - 1
|
||||
for i := n; i > 0; i-- {
|
||||
// Swap 2n-1th entry to top.
|
||||
so, err := s.nipN(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.PushByteArray(so)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OverN copies N items N items back to the top of the stack.
|
||||
//
|
||||
// Stack transformation:
|
||||
// OverN(1): [... x1 x2 x3] -> [... x1 x2 x3 x2]
|
||||
// OverN(2): [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2]
|
||||
func (s *stack) OverN(n int32) error {
|
||||
if n < 1 {
|
||||
str := fmt.Sprintf("attempt to perform over on %d stack items",
|
||||
n)
|
||||
return scriptError(ErrInvalidStackOperation, str)
|
||||
}
|
||||
|
||||
// Copy 2n-1th entry to top of the stack.
|
||||
entry := 2*n - 1
|
||||
for ; n > 0; n-- {
|
||||
so, err := s.PeekByteArray(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.PushByteArray(so)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PickN copies the item N items back in the stack to the top.
|
||||
//
|
||||
// Stack transformation:
|
||||
// PickN(0): [x1 x2 x3] -> [x1 x2 x3 x3]
|
||||
// PickN(1): [x1 x2 x3] -> [x1 x2 x3 x2]
|
||||
// PickN(2): [x1 x2 x3] -> [x1 x2 x3 x1]
|
||||
func (s *stack) PickN(n int32) error {
|
||||
so, err := s.PeekByteArray(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.PushByteArray(so)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RollN moves the item N items back in the stack to the top.
|
||||
//
|
||||
// Stack transformation:
|
||||
// RollN(0): [x1 x2 x3] -> [x1 x2 x3]
|
||||
// RollN(1): [x1 x2 x3] -> [x1 x3 x2]
|
||||
// RollN(2): [x1 x2 x3] -> [x2 x3 x1]
|
||||
func (s *stack) RollN(n int32) error {
|
||||
so, err := s.nipN(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.PushByteArray(so)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns the stack in a readable format.
|
||||
func (s *stack) String() string {
|
||||
var result string
|
||||
for _, stack := range s.stk {
|
||||
if len(stack) == 0 {
|
||||
result += "00000000 <empty>\n"
|
||||
}
|
||||
result += hex.Dump(stack)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
707
vendor/github.com/btcsuite/btcd/txscript/standard.go
generated
vendored
Normal file
707
vendor/github.com/btcsuite/btcd/txscript/standard.go
generated
vendored
Normal file
@@ -0,0 +1,707 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// MaxDataCarrierSize is the maximum number of bytes allowed in pushed
|
||||
// data to be considered a nulldata transaction
|
||||
MaxDataCarrierSize = 80
|
||||
|
||||
// StandardVerifyFlags are the script flags which are used when
|
||||
// executing transaction scripts to enforce additional checks which
|
||||
// are required for the script to be considered standard. These checks
|
||||
// help reduce issues related to transaction malleability as well as
|
||||
// allow pay-to-script hash transactions. Note these flags are
|
||||
// different than what is required for the consensus rules in that they
|
||||
// are more strict.
|
||||
//
|
||||
// TODO: This definition does not belong here. It belongs in a policy
|
||||
// package.
|
||||
StandardVerifyFlags = ScriptBip16 |
|
||||
ScriptVerifyDERSignatures |
|
||||
ScriptVerifyStrictEncoding |
|
||||
ScriptVerifyMinimalData |
|
||||
ScriptStrictMultiSig |
|
||||
ScriptDiscourageUpgradableNops |
|
||||
ScriptVerifyCleanStack |
|
||||
ScriptVerifyNullFail |
|
||||
ScriptVerifyCheckLockTimeVerify |
|
||||
ScriptVerifyCheckSequenceVerify |
|
||||
ScriptVerifyLowS |
|
||||
ScriptStrictMultiSig |
|
||||
ScriptVerifyWitness |
|
||||
ScriptVerifyDiscourageUpgradeableWitnessProgram |
|
||||
ScriptVerifyMinimalIf |
|
||||
ScriptVerifyWitnessPubKeyType
|
||||
)
|
||||
|
||||
// ScriptClass is an enumeration for the list of standard types of script.
|
||||
type ScriptClass byte
|
||||
|
||||
// Classes of script payment known about in the blockchain.
|
||||
const (
|
||||
NonStandardTy ScriptClass = iota // None of the recognized forms.
|
||||
PubKeyTy // Pay pubkey.
|
||||
PubKeyHashTy // Pay pubkey hash.
|
||||
WitnessV0PubKeyHashTy // Pay witness pubkey hash.
|
||||
ScriptHashTy // Pay to script hash.
|
||||
WitnessV0ScriptHashTy // Pay to witness script hash.
|
||||
MultiSigTy // Multi signature.
|
||||
NullDataTy // Empty data-only (provably prunable).
|
||||
)
|
||||
|
||||
// scriptClassToName houses the human-readable strings which describe each
|
||||
// script class.
|
||||
var scriptClassToName = []string{
|
||||
NonStandardTy: "nonstandard",
|
||||
PubKeyTy: "pubkey",
|
||||
PubKeyHashTy: "pubkeyhash",
|
||||
WitnessV0PubKeyHashTy: "witness_v0_keyhash",
|
||||
ScriptHashTy: "scripthash",
|
||||
WitnessV0ScriptHashTy: "witness_v0_scripthash",
|
||||
MultiSigTy: "multisig",
|
||||
NullDataTy: "nulldata",
|
||||
}
|
||||
|
||||
// String implements the Stringer interface by returning the name of
|
||||
// the enum script class. If the enum is invalid then "Invalid" will be
|
||||
// returned.
|
||||
func (t ScriptClass) String() string {
|
||||
if int(t) > len(scriptClassToName) || int(t) < 0 {
|
||||
return "Invalid"
|
||||
}
|
||||
return scriptClassToName[t]
|
||||
}
|
||||
|
||||
// isPubkey returns true if the script passed is a pay-to-pubkey transaction,
|
||||
// false otherwise.
|
||||
func isPubkey(pops []parsedOpcode) bool {
|
||||
// Valid pubkeys are either 33 or 65 bytes.
|
||||
return len(pops) == 2 &&
|
||||
(len(pops[0].data) == 33 || len(pops[0].data) == 65) &&
|
||||
pops[1].opcode.value == OP_CHECKSIG
|
||||
}
|
||||
|
||||
// isPubkeyHash returns true if the script passed is a pay-to-pubkey-hash
|
||||
// transaction, false otherwise.
|
||||
func isPubkeyHash(pops []parsedOpcode) bool {
|
||||
return len(pops) == 5 &&
|
||||
pops[0].opcode.value == OP_DUP &&
|
||||
pops[1].opcode.value == OP_HASH160 &&
|
||||
pops[2].opcode.value == OP_DATA_20 &&
|
||||
pops[3].opcode.value == OP_EQUALVERIFY &&
|
||||
pops[4].opcode.value == OP_CHECKSIG
|
||||
|
||||
}
|
||||
|
||||
// isMultiSig returns true if the passed script is a multisig transaction, false
|
||||
// otherwise.
|
||||
func isMultiSig(pops []parsedOpcode) bool {
|
||||
// The absolute minimum is 1 pubkey:
|
||||
// OP_0/OP_1-16 <pubkey> OP_1 OP_CHECKMULTISIG
|
||||
l := len(pops)
|
||||
if l < 4 {
|
||||
return false
|
||||
}
|
||||
if !isSmallInt(pops[0].opcode) {
|
||||
return false
|
||||
}
|
||||
if !isSmallInt(pops[l-2].opcode) {
|
||||
return false
|
||||
}
|
||||
if pops[l-1].opcode.value != OP_CHECKMULTISIG {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify the number of pubkeys specified matches the actual number
|
||||
// of pubkeys provided.
|
||||
if l-2-1 != asSmallInt(pops[l-2].opcode) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, pop := range pops[1 : l-2] {
|
||||
// Valid pubkeys are either 33 or 65 bytes.
|
||||
if len(pop.data) != 33 && len(pop.data) != 65 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isNullData returns true if the passed script is a null data transaction,
|
||||
// false otherwise.
|
||||
func isNullData(pops []parsedOpcode) bool {
|
||||
// A nulldata transaction is either a single OP_RETURN or an
|
||||
// OP_RETURN SMALLDATA (where SMALLDATA is a data push up to
|
||||
// MaxDataCarrierSize bytes).
|
||||
l := len(pops)
|
||||
if l == 1 && pops[0].opcode.value == OP_RETURN {
|
||||
return true
|
||||
}
|
||||
|
||||
return l == 2 &&
|
||||
pops[0].opcode.value == OP_RETURN &&
|
||||
(isSmallInt(pops[1].opcode) || pops[1].opcode.value <=
|
||||
OP_PUSHDATA4) &&
|
||||
len(pops[1].data) <= MaxDataCarrierSize
|
||||
}
|
||||
|
||||
// scriptType returns the type of the script being inspected from the known
|
||||
// standard types.
|
||||
func typeOfScript(pops []parsedOpcode) ScriptClass {
|
||||
if isPubkey(pops) {
|
||||
return PubKeyTy
|
||||
} else if isPubkeyHash(pops) {
|
||||
return PubKeyHashTy
|
||||
} else if isWitnessPubKeyHash(pops) {
|
||||
return WitnessV0PubKeyHashTy
|
||||
} else if isScriptHash(pops) {
|
||||
return ScriptHashTy
|
||||
} else if isWitnessScriptHash(pops) {
|
||||
return WitnessV0ScriptHashTy
|
||||
} else if isMultiSig(pops) {
|
||||
return MultiSigTy
|
||||
} else if isNullData(pops) {
|
||||
return NullDataTy
|
||||
}
|
||||
return NonStandardTy
|
||||
}
|
||||
|
||||
// GetScriptClass returns the class of the script passed.
|
||||
//
|
||||
// NonStandardTy will be returned when the script does not parse.
|
||||
func GetScriptClass(script []byte) ScriptClass {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return NonStandardTy
|
||||
}
|
||||
return typeOfScript(pops)
|
||||
}
|
||||
|
||||
// expectedInputs returns the number of arguments required by a script.
|
||||
// If the script is of unknown type such that the number can not be determined
|
||||
// then -1 is returned. We are an internal function and thus assume that class
|
||||
// is the real class of pops (and we can thus assume things that were determined
|
||||
// while finding out the type).
|
||||
func expectedInputs(pops []parsedOpcode, class ScriptClass) int {
|
||||
switch class {
|
||||
case PubKeyTy:
|
||||
return 1
|
||||
|
||||
case PubKeyHashTy:
|
||||
return 2
|
||||
|
||||
case WitnessV0PubKeyHashTy:
|
||||
return 2
|
||||
|
||||
case ScriptHashTy:
|
||||
// Not including script. That is handled by the caller.
|
||||
return 1
|
||||
|
||||
case WitnessV0ScriptHashTy:
|
||||
// Not including script. That is handled by the caller.
|
||||
return 1
|
||||
|
||||
case MultiSigTy:
|
||||
// Standard multisig has a push a small number for the number
|
||||
// of sigs and number of keys. Check the first push instruction
|
||||
// to see how many arguments are expected. typeOfScript already
|
||||
// checked this so we know it'll be a small int. Also, due to
|
||||
// the original bitcoind bug where OP_CHECKMULTISIG pops an
|
||||
// additional item from the stack, add an extra expected input
|
||||
// for the extra push that is required to compensate.
|
||||
return asSmallInt(pops[0].opcode) + 1
|
||||
|
||||
case NullDataTy:
|
||||
fallthrough
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
// ScriptInfo houses information about a script pair that is determined by
|
||||
// CalcScriptInfo.
|
||||
type ScriptInfo struct {
|
||||
// PkScriptClass is the class of the public key script and is equivalent
|
||||
// to calling GetScriptClass on it.
|
||||
PkScriptClass ScriptClass
|
||||
|
||||
// NumInputs is the number of inputs provided by the public key script.
|
||||
NumInputs int
|
||||
|
||||
// ExpectedInputs is the number of outputs required by the signature
|
||||
// script and any pay-to-script-hash scripts. The number will be -1 if
|
||||
// unknown.
|
||||
ExpectedInputs int
|
||||
|
||||
// SigOps is the number of signature operations in the script pair.
|
||||
SigOps int
|
||||
}
|
||||
|
||||
// CalcScriptInfo returns a structure providing data about the provided script
|
||||
// pair. It will error if the pair is in someway invalid such that they can not
|
||||
// be analysed, i.e. if they do not parse or the pkScript is not a push-only
|
||||
// script
|
||||
func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness,
|
||||
bip16, segwit bool) (*ScriptInfo, error) {
|
||||
|
||||
sigPops, err := parseScript(sigScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkPops, err := parseScript(pkScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Push only sigScript makes little sense.
|
||||
si := new(ScriptInfo)
|
||||
si.PkScriptClass = typeOfScript(pkPops)
|
||||
|
||||
// Can't have a signature script that doesn't just push data.
|
||||
if !isPushOnly(sigPops) {
|
||||
return nil, scriptError(ErrNotPushOnly,
|
||||
"signature script is not push only")
|
||||
}
|
||||
|
||||
si.ExpectedInputs = expectedInputs(pkPops, si.PkScriptClass)
|
||||
|
||||
switch {
|
||||
// Count sigops taking into account pay-to-script-hash.
|
||||
case si.PkScriptClass == ScriptHashTy && bip16 && !segwit:
|
||||
// The pay-to-hash-script is the final data push of the
|
||||
// signature script.
|
||||
script := sigPops[len(sigPops)-1].data
|
||||
shPops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shInputs := expectedInputs(shPops, typeOfScript(shPops))
|
||||
if shInputs == -1 {
|
||||
si.ExpectedInputs = -1
|
||||
} else {
|
||||
si.ExpectedInputs += shInputs
|
||||
}
|
||||
si.SigOps = getSigOpCount(shPops, true)
|
||||
|
||||
// All entries pushed to stack (or are OP_RESERVED and exec
|
||||
// will fail).
|
||||
si.NumInputs = len(sigPops)
|
||||
|
||||
// If segwit is active, and this is a regular p2wkh output, then we'll
|
||||
// treat the script as a p2pkh output in essence.
|
||||
case si.PkScriptClass == WitnessV0PubKeyHashTy && segwit:
|
||||
|
||||
si.SigOps = GetWitnessSigOpCount(sigScript, pkScript, witness)
|
||||
si.NumInputs = len(witness)
|
||||
|
||||
// We'll attempt to detect the nested p2sh case so we can accurately
|
||||
// count the signature operations involved.
|
||||
case si.PkScriptClass == ScriptHashTy &&
|
||||
IsWitnessProgram(sigScript[1:]) && bip16 && segwit:
|
||||
|
||||
// Extract the pushed witness program from the sigScript so we
|
||||
// can determine the number of expected inputs.
|
||||
pkPops, _ := parseScript(sigScript[1:])
|
||||
shInputs := expectedInputs(pkPops, typeOfScript(pkPops))
|
||||
if shInputs == -1 {
|
||||
si.ExpectedInputs = -1
|
||||
} else {
|
||||
si.ExpectedInputs += shInputs
|
||||
}
|
||||
|
||||
si.SigOps = GetWitnessSigOpCount(sigScript, pkScript, witness)
|
||||
|
||||
si.NumInputs = len(witness)
|
||||
si.NumInputs += len(sigPops)
|
||||
|
||||
// If segwit is active, and this is a p2wsh output, then we'll need to
|
||||
// examine the witness script to generate accurate script info.
|
||||
case si.PkScriptClass == WitnessV0ScriptHashTy && segwit:
|
||||
// The witness script is the final element of the witness
|
||||
// stack.
|
||||
witnessScript := witness[len(witness)-1]
|
||||
pops, _ := parseScript(witnessScript)
|
||||
|
||||
shInputs := expectedInputs(pops, typeOfScript(pops))
|
||||
if shInputs == -1 {
|
||||
si.ExpectedInputs = -1
|
||||
} else {
|
||||
si.ExpectedInputs += shInputs
|
||||
}
|
||||
|
||||
si.SigOps = GetWitnessSigOpCount(sigScript, pkScript, witness)
|
||||
si.NumInputs = len(witness)
|
||||
|
||||
default:
|
||||
si.SigOps = getSigOpCount(pkPops, true)
|
||||
|
||||
// All entries pushed to stack (or are OP_RESERVED and exec
|
||||
// will fail).
|
||||
si.NumInputs = len(sigPops)
|
||||
}
|
||||
|
||||
return si, nil
|
||||
}
|
||||
|
||||
// CalcMultiSigStats returns the number of public keys and signatures from
|
||||
// a multi-signature transaction script. The passed script MUST already be
|
||||
// known to be a multi-signature script.
|
||||
func CalcMultiSigStats(script []byte) (int, int, error) {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
// A multi-signature script is of the pattern:
|
||||
// NUM_SIGS PUBKEY PUBKEY PUBKEY... NUM_PUBKEYS OP_CHECKMULTISIG
|
||||
// Therefore the number of signatures is the oldest item on the stack
|
||||
// and the number of pubkeys is the 2nd to last. Also, the absolute
|
||||
// minimum for a multi-signature script is 1 pubkey, so at least 4
|
||||
// items must be on the stack per:
|
||||
// OP_1 PUBKEY OP_1 OP_CHECKMULTISIG
|
||||
if len(pops) < 4 {
|
||||
str := fmt.Sprintf("script %x is not a multisig script", script)
|
||||
return 0, 0, scriptError(ErrNotMultisigScript, str)
|
||||
}
|
||||
|
||||
numSigs := asSmallInt(pops[0].opcode)
|
||||
numPubKeys := asSmallInt(pops[len(pops)-2].opcode)
|
||||
return numPubKeys, numSigs, nil
|
||||
}
|
||||
|
||||
// payToPubKeyHashScript creates a new script to pay a transaction
|
||||
// output to a 20-byte pubkey hash. It is expected that the input is a valid
|
||||
// hash.
|
||||
func payToPubKeyHashScript(pubKeyHash []byte) ([]byte, error) {
|
||||
return NewScriptBuilder().AddOp(OP_DUP).AddOp(OP_HASH160).
|
||||
AddData(pubKeyHash).AddOp(OP_EQUALVERIFY).AddOp(OP_CHECKSIG).
|
||||
Script()
|
||||
}
|
||||
|
||||
// payToWitnessPubKeyHashScript creates a new script to pay to a version 0
|
||||
// pubkey hash witness program. The passed hash is expected to be valid.
|
||||
func payToWitnessPubKeyHashScript(pubKeyHash []byte) ([]byte, error) {
|
||||
return NewScriptBuilder().AddOp(OP_0).AddData(pubKeyHash).Script()
|
||||
}
|
||||
|
||||
// payToScriptHashScript creates a new script to pay a transaction output to a
|
||||
// script hash. It is expected that the input is a valid hash.
|
||||
func payToScriptHashScript(scriptHash []byte) ([]byte, error) {
|
||||
return NewScriptBuilder().AddOp(OP_HASH160).AddData(scriptHash).
|
||||
AddOp(OP_EQUAL).Script()
|
||||
}
|
||||
|
||||
// payToWitnessPubKeyHashScript creates a new script to pay to a version 0
|
||||
// script hash witness program. The passed hash is expected to be valid.
|
||||
func payToWitnessScriptHashScript(scriptHash []byte) ([]byte, error) {
|
||||
return NewScriptBuilder().AddOp(OP_0).AddData(scriptHash).Script()
|
||||
}
|
||||
|
||||
// payToPubkeyScript creates a new script to pay a transaction output to a
|
||||
// public key. It is expected that the input is a valid pubkey.
|
||||
func payToPubKeyScript(serializedPubKey []byte) ([]byte, error) {
|
||||
return NewScriptBuilder().AddData(serializedPubKey).
|
||||
AddOp(OP_CHECKSIG).Script()
|
||||
}
|
||||
|
||||
// PayToAddrScript creates a new script to pay a transaction output to a the
|
||||
// specified address.
|
||||
func PayToAddrScript(addr btcutil.Address) ([]byte, error) {
|
||||
const nilAddrErrStr = "unable to generate payment script for nil address"
|
||||
|
||||
switch addr := addr.(type) {
|
||||
case *btcutil.AddressPubKeyHash:
|
||||
if addr == nil {
|
||||
return nil, scriptError(ErrUnsupportedAddress,
|
||||
nilAddrErrStr)
|
||||
}
|
||||
return payToPubKeyHashScript(addr.ScriptAddress())
|
||||
|
||||
case *btcutil.AddressScriptHash:
|
||||
if addr == nil {
|
||||
return nil, scriptError(ErrUnsupportedAddress,
|
||||
nilAddrErrStr)
|
||||
}
|
||||
return payToScriptHashScript(addr.ScriptAddress())
|
||||
|
||||
case *btcutil.AddressPubKey:
|
||||
if addr == nil {
|
||||
return nil, scriptError(ErrUnsupportedAddress,
|
||||
nilAddrErrStr)
|
||||
}
|
||||
return payToPubKeyScript(addr.ScriptAddress())
|
||||
|
||||
case *btcutil.AddressWitnessPubKeyHash:
|
||||
if addr == nil {
|
||||
return nil, scriptError(ErrUnsupportedAddress,
|
||||
nilAddrErrStr)
|
||||
}
|
||||
return payToWitnessPubKeyHashScript(addr.ScriptAddress())
|
||||
case *btcutil.AddressWitnessScriptHash:
|
||||
if addr == nil {
|
||||
return nil, scriptError(ErrUnsupportedAddress,
|
||||
nilAddrErrStr)
|
||||
}
|
||||
return payToWitnessScriptHashScript(addr.ScriptAddress())
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("unable to generate payment script for unsupported "+
|
||||
"address type %T", addr)
|
||||
return nil, scriptError(ErrUnsupportedAddress, str)
|
||||
}
|
||||
|
||||
// NullDataScript creates a provably-prunable script containing OP_RETURN
|
||||
// followed by the passed data. An Error with the error code ErrTooMuchNullData
|
||||
// will be returned if the length of the passed data exceeds MaxDataCarrierSize.
|
||||
func NullDataScript(data []byte) ([]byte, error) {
|
||||
if len(data) > MaxDataCarrierSize {
|
||||
str := fmt.Sprintf("data size %d is larger than max "+
|
||||
"allowed size %d", len(data), MaxDataCarrierSize)
|
||||
return nil, scriptError(ErrTooMuchNullData, str)
|
||||
}
|
||||
|
||||
return NewScriptBuilder().AddOp(OP_RETURN).AddData(data).Script()
|
||||
}
|
||||
|
||||
// MultiSigScript returns a valid script for a multisignature redemption where
|
||||
// nrequired of the keys in pubkeys are required to have signed the transaction
|
||||
// for success. An Error with the error code ErrTooManyRequiredSigs will be
|
||||
// returned if nrequired is larger than the number of keys provided.
|
||||
func MultiSigScript(pubkeys []*btcutil.AddressPubKey, nrequired int) ([]byte, error) {
|
||||
if len(pubkeys) < nrequired {
|
||||
str := fmt.Sprintf("unable to generate multisig script with "+
|
||||
"%d required signatures when there are only %d public "+
|
||||
"keys available", nrequired, len(pubkeys))
|
||||
return nil, scriptError(ErrTooManyRequiredSigs, str)
|
||||
}
|
||||
|
||||
builder := NewScriptBuilder().AddInt64(int64(nrequired))
|
||||
for _, key := range pubkeys {
|
||||
builder.AddData(key.ScriptAddress())
|
||||
}
|
||||
builder.AddInt64(int64(len(pubkeys)))
|
||||
builder.AddOp(OP_CHECKMULTISIG)
|
||||
|
||||
return builder.Script()
|
||||
}
|
||||
|
||||
// PushedData returns an array of byte slices containing any pushed data found
|
||||
// in the passed script. This includes OP_0, but not OP_1 - OP_16.
|
||||
func PushedData(script []byte) ([][]byte, error) {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var data [][]byte
|
||||
for _, pop := range pops {
|
||||
if pop.data != nil {
|
||||
data = append(data, pop.data)
|
||||
} else if pop.opcode.value == OP_0 {
|
||||
data = append(data, nil)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ExtractPkScriptAddrs returns the type of script, addresses and required
|
||||
// signatures associated with the passed PkScript. Note that it only works for
|
||||
// 'standard' transaction script types. Any data such as public keys which are
|
||||
// invalid are omitted from the results.
|
||||
func ExtractPkScriptAddrs(pkScript []byte, chainParams *chaincfg.Params) (ScriptClass, []btcutil.Address, int, error) {
|
||||
var addrs []btcutil.Address
|
||||
var requiredSigs int
|
||||
|
||||
// No valid addresses or required signatures if the script doesn't
|
||||
// parse.
|
||||
pops, err := parseScript(pkScript)
|
||||
if err != nil {
|
||||
return NonStandardTy, nil, 0, err
|
||||
}
|
||||
|
||||
scriptClass := typeOfScript(pops)
|
||||
switch scriptClass {
|
||||
case PubKeyHashTy:
|
||||
// A pay-to-pubkey-hash script is of the form:
|
||||
// OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
// Therefore the pubkey hash is the 3rd item on the stack.
|
||||
// Skip the pubkey hash if it's invalid for some reason.
|
||||
requiredSigs = 1
|
||||
addr, err := btcutil.NewAddressPubKeyHash(pops[2].data,
|
||||
chainParams)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
case WitnessV0PubKeyHashTy:
|
||||
// A pay-to-witness-pubkey-hash script is of thw form:
|
||||
// OP_0 <20-byte hash>
|
||||
// Therefore, the pubkey hash is the second item on the stack.
|
||||
// Skip the pubkey hash if it's invalid for some reason.
|
||||
requiredSigs = 1
|
||||
addr, err := btcutil.NewAddressWitnessPubKeyHash(pops[1].data,
|
||||
chainParams)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
case PubKeyTy:
|
||||
// A pay-to-pubkey script is of the form:
|
||||
// <pubkey> OP_CHECKSIG
|
||||
// Therefore the pubkey is the first item on the stack.
|
||||
// Skip the pubkey if it's invalid for some reason.
|
||||
requiredSigs = 1
|
||||
addr, err := btcutil.NewAddressPubKey(pops[0].data, chainParams)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
case ScriptHashTy:
|
||||
// A pay-to-script-hash script is of the form:
|
||||
// OP_HASH160 <scripthash> OP_EQUAL
|
||||
// Therefore the script hash is the 2nd item on the stack.
|
||||
// Skip the script hash if it's invalid for some reason.
|
||||
requiredSigs = 1
|
||||
addr, err := btcutil.NewAddressScriptHashFromHash(pops[1].data,
|
||||
chainParams)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
case WitnessV0ScriptHashTy:
|
||||
// A pay-to-witness-script-hash script is of the form:
|
||||
// OP_0 <32-byte hash>
|
||||
// Therefore, the script hash is the second item on the stack.
|
||||
// Skip the script hash if it's invalid for some reason.
|
||||
requiredSigs = 1
|
||||
addr, err := btcutil.NewAddressWitnessScriptHash(pops[1].data,
|
||||
chainParams)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
case MultiSigTy:
|
||||
// A multi-signature script is of the form:
|
||||
// <numsigs> <pubkey> <pubkey> <pubkey>... <numpubkeys> OP_CHECKMULTISIG
|
||||
// Therefore the number of required signatures is the 1st item
|
||||
// on the stack and the number of public keys is the 2nd to last
|
||||
// item on the stack.
|
||||
requiredSigs = asSmallInt(pops[0].opcode)
|
||||
numPubKeys := asSmallInt(pops[len(pops)-2].opcode)
|
||||
|
||||
// Extract the public keys while skipping any that are invalid.
|
||||
addrs = make([]btcutil.Address, 0, numPubKeys)
|
||||
for i := 0; i < numPubKeys; i++ {
|
||||
addr, err := btcutil.NewAddressPubKey(pops[i+1].data,
|
||||
chainParams)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
}
|
||||
|
||||
case NullDataTy:
|
||||
// Null data transactions have no addresses or required
|
||||
// signatures.
|
||||
|
||||
case NonStandardTy:
|
||||
// Don't attempt to extract addresses or required signatures for
|
||||
// nonstandard transactions.
|
||||
}
|
||||
|
||||
return scriptClass, addrs, requiredSigs, nil
|
||||
}
|
||||
|
||||
// AtomicSwapDataPushes houses the data pushes found in atomic swap contracts.
|
||||
type AtomicSwapDataPushes struct {
|
||||
RecipientHash160 [20]byte
|
||||
RefundHash160 [20]byte
|
||||
SecretHash [32]byte
|
||||
SecretSize int64
|
||||
LockTime int64
|
||||
}
|
||||
|
||||
// ExtractAtomicSwapDataPushes returns the data pushes from an atomic swap
|
||||
// contract. If the script is not an atomic swap contract,
|
||||
// ExtractAtomicSwapDataPushes returns (nil, nil). Non-nil errors are returned
|
||||
// for unparsable scripts.
|
||||
//
|
||||
// NOTE: Atomic swaps are not considered standard script types by the dcrd
|
||||
// mempool policy and should be used with P2SH. The atomic swap format is also
|
||||
// expected to change to use a more secure hash function in the future.
|
||||
//
|
||||
// This function is only defined in the txscript package due to API limitations
|
||||
// which prevent callers using txscript to parse nonstandard scripts.
|
||||
func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDataPushes, error) {
|
||||
pops, err := parseScript(pkScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(pops) != 20 {
|
||||
return nil, nil
|
||||
}
|
||||
isAtomicSwap := pops[0].opcode.value == OP_IF &&
|
||||
pops[1].opcode.value == OP_SIZE &&
|
||||
canonicalPush(pops[2]) &&
|
||||
pops[3].opcode.value == OP_EQUALVERIFY &&
|
||||
pops[4].opcode.value == OP_SHA256 &&
|
||||
pops[5].opcode.value == OP_DATA_32 &&
|
||||
pops[6].opcode.value == OP_EQUALVERIFY &&
|
||||
pops[7].opcode.value == OP_DUP &&
|
||||
pops[8].opcode.value == OP_HASH160 &&
|
||||
pops[9].opcode.value == OP_DATA_20 &&
|
||||
pops[10].opcode.value == OP_ELSE &&
|
||||
canonicalPush(pops[11]) &&
|
||||
pops[12].opcode.value == OP_CHECKLOCKTIMEVERIFY &&
|
||||
pops[13].opcode.value == OP_DROP &&
|
||||
pops[14].opcode.value == OP_DUP &&
|
||||
pops[15].opcode.value == OP_HASH160 &&
|
||||
pops[16].opcode.value == OP_DATA_20 &&
|
||||
pops[17].opcode.value == OP_ENDIF &&
|
||||
pops[18].opcode.value == OP_EQUALVERIFY &&
|
||||
pops[19].opcode.value == OP_CHECKSIG
|
||||
if !isAtomicSwap {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
pushes := new(AtomicSwapDataPushes)
|
||||
copy(pushes.SecretHash[:], pops[5].data)
|
||||
copy(pushes.RecipientHash160[:], pops[9].data)
|
||||
copy(pushes.RefundHash160[:], pops[16].data)
|
||||
if pops[2].data != nil {
|
||||
locktime, err := makeScriptNum(pops[2].data, true, 5)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
pushes.SecretSize = int64(locktime)
|
||||
} else if op := pops[2].opcode; isSmallInt(op) {
|
||||
pushes.SecretSize = int64(asSmallInt(op))
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
if pops[11].data != nil {
|
||||
locktime, err := makeScriptNum(pops[11].data, true, 5)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
pushes.LockTime = int64(locktime)
|
||||
} else if op := pops[11].opcode; isSmallInt(op) {
|
||||
pushes.LockTime = int64(asSmallInt(op))
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
return pushes, nil
|
||||
}
|
||||
Reference in New Issue
Block a user