txscript

package
v1.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 29, 2024 License: ISC Imports: 15 Imported by: 0

README

txscript

ISC License GoDoc

Package txscript implements the kobra transaction script language. There is a comprehensive test suite.

Pyrin Scripts

Pyrin provides a stack-based, FORTH-like language for the scripts in the kobra transactions. This language is not turing complete although it is still fairly powerful.

Examples

Documentation

Overview

Package txscript implements the kobra transaction script language.

This package provides data structures and functions to parse and execute kobra transaction scripts.

Script Overview

Pyrin transaction scripts are written in a stack-base, FORTH-like language.

The kobra 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.

Typical kobra 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 kobra.

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.

Index

Examples

Constants

View Source
const (
	// MaxStackSize is the maximum combined height of stack and alt stack
	// during execution.
	MaxStackSize = 244

	// MaxScriptSize is the maximum allowed length of a raw script.
	MaxScriptSize = 10000
)
View Source
const (
	Op0                   = 0x00 // 0
	OpFalse               = 0x00 // 0 - AKA Op0
	OpData1               = 0x01 // 1
	OpData2               = 0x02 // 2
	OpData3               = 0x03 // 3
	OpData4               = 0x04 // 4
	OpData5               = 0x05 // 5
	OpData6               = 0x06 // 6
	OpData7               = 0x07 // 7
	OpData8               = 0x08 // 8
	OpData9               = 0x09 // 9
	OpData10              = 0x0a // 10
	OpData11              = 0x0b // 11
	OpData12              = 0x0c // 12
	OpData13              = 0x0d // 13
	OpData14              = 0x0e // 14
	OpData15              = 0x0f // 15
	OpData16              = 0x10 // 16
	OpData17              = 0x11 // 17
	OpData18              = 0x12 // 18
	OpData19              = 0x13 // 19
	OpData20              = 0x14 // 20
	OpData21              = 0x15 // 21
	OpData22              = 0x16 // 22
	OpData23              = 0x17 // 23
	OpData24              = 0x18 // 24
	OpData25              = 0x19 // 25
	OpData26              = 0x1a // 26
	OpData27              = 0x1b // 27
	OpData28              = 0x1c // 28
	OpData29              = 0x1d // 29
	OpData30              = 0x1e // 30
	OpData31              = 0x1f // 31
	OpData32              = 0x20 // 32
	OpData33              = 0x21 // 33
	OpData34              = 0x22 // 34
	OpData35              = 0x23 // 35
	OpData36              = 0x24 // 36
	OpData37              = 0x25 // 37
	OpData38              = 0x26 // 38
	OpData39              = 0x27 // 39
	OpData40              = 0x28 // 40
	OpData41              = 0x29 // 41
	OpData42              = 0x2a // 42
	OpData43              = 0x2b // 43
	OpData44              = 0x2c // 44
	OpData45              = 0x2d // 45
	OpData46              = 0x2e // 46
	OpData47              = 0x2f // 47
	OpData48              = 0x30 // 48
	OpData49              = 0x31 // 49
	OpData50              = 0x32 // 50
	OpData51              = 0x33 // 51
	OpData52              = 0x34 // 52
	OpData53              = 0x35 // 53
	OpData54              = 0x36 // 54
	OpData55              = 0x37 // 55
	OpData56              = 0x38 // 56
	OpData57              = 0x39 // 57
	OpData58              = 0x3a // 58
	OpData59              = 0x3b // 59
	OpData60              = 0x3c // 60
	OpData61              = 0x3d // 61
	OpData62              = 0x3e // 62
	OpData63              = 0x3f // 63
	OpData64              = 0x40 // 64
	OpData65              = 0x41 // 65
	OpData66              = 0x42 // 66
	OpData67              = 0x43 // 67
	OpData68              = 0x44 // 68
	OpData69              = 0x45 // 69
	OpData70              = 0x46 // 70
	OpData71              = 0x47 // 71
	OpData72              = 0x48 // 72
	OpData73              = 0x49 // 73
	OpData74              = 0x4a // 74
	OpData75              = 0x4b // 75
	OpPushData1           = 0x4c // 76
	OpPushData2           = 0x4d // 77
	OpPushData4           = 0x4e // 78
	Op1Negate             = 0x4f // 79
	OpReserved            = 0x50 // 80
	Op1                   = 0x51 // 81 - AKA OpTrue
	OpTrue                = 0x51 // 81
	Op2                   = 0x52 // 82
	Op3                   = 0x53 // 83
	Op4                   = 0x54 // 84
	Op5                   = 0x55 // 85
	Op6                   = 0x56 // 86
	Op7                   = 0x57 // 87
	Op8                   = 0x58 // 88
	Op9                   = 0x59 // 89
	Op10                  = 0x5a // 90
	Op11                  = 0x5b // 91
	Op12                  = 0x5c // 92
	Op13                  = 0x5d // 93
	Op14                  = 0x5e // 94
	Op15                  = 0x5f // 95
	Op16                  = 0x60 // 96
	OpNop                 = 0x61 // 97
	OpVer                 = 0x62 // 98
	OpIf                  = 0x63 // 99
	OpNotIf               = 0x64 // 100
	OpVerIf               = 0x65 // 101
	OpVerNotIf            = 0x66 // 102
	OpElse                = 0x67 // 103
	OpEndIf               = 0x68 // 104
	OpVerify              = 0x69 // 105
	OpReturn              = 0x6a // 106
	OpToAltStack          = 0x6b // 107
	OpFromAltStack        = 0x6c // 108
	Op2Drop               = 0x6d // 109
	Op2Dup                = 0x6e // 110
	Op3Dup                = 0x6f // 111
	Op2Over               = 0x70 // 112
	Op2Rot                = 0x71 // 113
	Op2Swap               = 0x72 // 114
	OpIfDup               = 0x73 // 115
	OpDepth               = 0x74 // 116
	OpDrop                = 0x75 // 117
	OpDup                 = 0x76 // 118
	OpNip                 = 0x77 // 119
	OpOver                = 0x78 // 120
	OpPick                = 0x79 // 121
	OpRoll                = 0x7a // 122
	OpRot                 = 0x7b // 123
	OpSwap                = 0x7c // 124
	OpTuck                = 0x7d // 125
	OpCat                 = 0x7e // 126
	OpSubStr              = 0x7f // 127
	OpLeft                = 0x80 // 128
	OpRight               = 0x81 // 129
	OpSize                = 0x82 // 130
	OpInvert              = 0x83 // 131
	OpAnd                 = 0x84 // 132
	OpOr                  = 0x85 // 133
	OpXor                 = 0x86 // 134
	OpEqual               = 0x87 // 135
	OpEqualVerify         = 0x88 // 136
	OpReserved1           = 0x89 // 137
	OpReserved2           = 0x8a // 138
	Op1Add                = 0x8b // 139
	Op1Sub                = 0x8c // 140
	Op2Mul                = 0x8d // 141
	Op2Div                = 0x8e // 142
	OpNegate              = 0x8f // 143
	OpAbs                 = 0x90 // 144
	OpNot                 = 0x91 // 145
	Op0NotEqual           = 0x92 // 146
	OpAdd                 = 0x93 // 147
	OpSub                 = 0x94 // 148
	OpMul                 = 0x95 // 149
	OpDiv                 = 0x96 // 150
	OpMod                 = 0x97 // 151
	OpLShift              = 0x98 // 152
	OpRShift              = 0x99 // 153
	OpBoolAnd             = 0x9a // 154
	OpBoolOr              = 0x9b // 155
	OpNumEqual            = 0x9c // 156
	OpNumEqualVerify      = 0x9d // 157
	OpNumNotEqual         = 0x9e // 158
	OpLessThan            = 0x9f // 159
	OpGreaterThan         = 0xa0 // 160
	OpLessThanOrEqual     = 0xa1 // 161
	OpGreaterThanOrEqual  = 0xa2 // 162
	OpMin                 = 0xa3 // 163
	OpMax                 = 0xa4 // 164
	OpWithin              = 0xa5 // 165
	OpUnknown166          = 0xa6 // 166
	OpUnknown167          = 0xa7 // 167
	OpSHA256              = 0xa8 // 168
	OpCheckMultiSigECDSA  = 0xa9 // 169
	OpBlake3              = 0xaa // 170
	OpCheckSigECDSA       = 0xab // 171
	OpCheckSig            = 0xac // 172
	OpCheckSigVerify      = 0xad // 173
	OpCheckMultiSig       = 0xae // 174
	OpCheckMultiSigVerify = 0xaf // 175
	OpCheckLockTimeVerify = 0xb0 // 176
	OpCheckSequenceVerify = 0xb1 // 177
	OpUnknown178          = 0xb2 // 178
	OpUnknown179          = 0xb3 // 179
	OpUnknown180          = 0xb4 // 180
	OpUnknown181          = 0xb5 // 181
	OpUnknown182          = 0xb6 // 182
	OpUnknown183          = 0xb7 // 183
	OpUnknown184          = 0xb8 // 184
	OpUnknown185          = 0xb9 // 185
	OpUnknown186          = 0xba // 186
	OpUnknown187          = 0xbb // 187
	OpUnknown188          = 0xbc // 188
	OpUnknown189          = 0xbd // 189
	OpUnknown190          = 0xbe // 190
	OpUnknown191          = 0xbf // 191
	OpUnknown192          = 0xc0 // 192
	OpUnknown193          = 0xc1 // 193
	OpUnknown194          = 0xc2 // 194
	OpUnknown195          = 0xc3 // 195
	OpUnknown196          = 0xc4 // 196
	OpUnknown197          = 0xc5 // 197
	OpUnknown198          = 0xc6 // 198
	OpUnknown199          = 0xc7 // 199
	OpUnknown200          = 0xc8 // 200
	OpUnknown201          = 0xc9 // 201
	OpUnknown202          = 0xca // 202
	OpUnknown203          = 0xcb // 203
	OpUnknown204          = 0xcc // 204
	OpUnknown205          = 0xcd // 205
	OpUnknown206          = 0xce // 206
	OpUnknown207          = 0xcf // 207
	OpUnknown208          = 0xd0 // 208
	OpUnknown209          = 0xd1 // 209
	OpUnknown210          = 0xd2 // 210
	OpUnknown211          = 0xd3 // 211
	OpUnknown212          = 0xd4 // 212
	OpUnknown213          = 0xd5 // 213
	OpUnknown214          = 0xd6 // 214
	OpUnknown215          = 0xd7 // 215
	OpUnknown216          = 0xd8 // 216
	OpUnknown217          = 0xd9 // 217
	OpUnknown218          = 0xda // 218
	OpUnknown219          = 0xdb // 219
	OpUnknown220          = 0xdc // 220
	OpUnknown221          = 0xdd // 221
	OpUnknown222          = 0xde // 222
	OpUnknown223          = 0xdf // 223
	OpUnknown224          = 0xe0 // 224
	OpUnknown225          = 0xe1 // 225
	OpUnknown226          = 0xe2 // 226
	OpUnknown227          = 0xe3 // 227
	OpUnknown228          = 0xe4 // 228
	OpUnknown229          = 0xe5 // 229
	OpUnknown230          = 0xe6 // 230
	OpUnknown231          = 0xe7 // 231
	OpUnknown232          = 0xe8 // 232
	OpUnknown233          = 0xe9 // 233
	OpUnknown234          = 0xea // 234
	OpUnknown235          = 0xeb // 235
	OpUnknown236          = 0xec // 236
	OpUnknown237          = 0xed // 237
	OpUnknown238          = 0xee // 238
	OpUnknown239          = 0xef // 239
	OpUnknown240          = 0xf0 // 240
	OpUnknown241          = 0xf1 // 241
	OpUnknown242          = 0xf2 // 242
	OpUnknown243          = 0xf3 // 243
	OpUnknown244          = 0xf4 // 244
	OpUnknown245          = 0xf5 // 245
	OpUnknown246          = 0xf6 // 246
	OpUnknown247          = 0xf7 // 247
	OpUnknown248          = 0xf8 // 248
	OpUnknown249          = 0xf9 // 249
	OpSmallInteger        = 0xfa // 250
	OpPubKeys             = 0xfb // 251
	OpUnknown252          = 0xfc // 252
	OpPubKeyHash          = 0xfd // 253
	OpPubKey              = 0xfe // 254
	OpInvalidOpCode       = 0xff // 255
)

These constants are the values of the kobra script opcodes.

View Source
const (
	OpCondFalse = 0
	OpCondTrue  = 1
	OpCondSkip  = 2
)

Conditional execution constants.

View Source
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.
)

These are the constants specified for maximums in individual scripts.

Variables

View Source
var OpcodeByName = make(map[string]byte)

OpcodeByName is a map that can be used to lookup an opcode by its human-readable name (OP_CHECKMULTISIG, OP_CHECKSIG, etc).

Functions

func DisasmString

func DisasmString(version uint16, buf []byte) (string, error)

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 GetPreciseSigOpCount

func GetPreciseSigOpCount(scriptSig []byte, scriptPubKey *externalapi.ScriptPublicKey, isP2SH bool) int

GetPreciseSigOpCount returns the number of signature operations in scriptPubKey. If p2sh 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 GetSigOpCount

func GetSigOpCount(script []byte) int

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 IsErrorCode

func IsErrorCode(err error, c ErrorCode) bool

IsErrorCode returns whether or not the provided error is a script error with the provided error code.

func IsPayToScriptHash

func IsPayToScriptHash(script *externalapi.ScriptPublicKey) bool

IsPayToScriptHash returns true if the script is in the standard pay-to-script-hash (P2SH) format, false otherwise.

func IsUnspendable

func IsUnspendable(scriptPubKey []byte) bool

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 PayToAddrScript

func PayToAddrScript(addr util.Address) (*externalapi.ScriptPublicKey, error)

PayToAddrScript creates a new script to pay a transaction output to a the specified address.

Example

This example demonstrates creating a script which pays to a kobra address. It also prints the created script hex and uses the DisasmString function to display the disassembled script.

package main

import (
	"fmt"

	"github.com/kobradag/kobrad/domain/consensus/utils/txscript"
	"github.com/kobradag/kobrad/util"
)

func main() {
	// Parse the address to send the coins to into a util.Address
	// which is useful to ensure the accuracy of the address and determine
	// the address type. It is also required for the upcoming call to
	// PayToAddrScript.
	addressStr := "kobra:qqj9fg59mptxkr9j0y53j5mwurcmda5mtza9n6v9pm9uj8h0wgk6u9aj94505"
	address, err := util.DecodeAddress(addressStr, util.Bech32PrefixPyrin)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Create a public key script that pays to the address.
	script, err := txscript.PayToAddrScript(address)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("Script Hex: %x\n", script.Script)

	disasm, err := txscript.DisasmString(script.Version, script.Script)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Script Disassembly:", disasm)
}
Output:

func PayToScriptHashScript

func PayToScriptHashScript(redeemScript []byte) ([]byte, error)

PayToScriptHashScript takes a script and returns an equivalent pay-to-script-hash script

func PayToScriptHashSignatureScript

func PayToScriptHashSignatureScript(redeemScript []byte, signature []byte) ([]byte, error)

PayToScriptHashSignatureScript generates a signature script that fits a pay-to-script-hash script

func PushedData

func PushedData(script []byte) ([][]byte, error)

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 RawTxInSignature

func RawTxInSignature(tx *externalapi.DomainTransaction, idx int, hashType consensushashing.SigHashType,
	key *secp256k1.SchnorrKeyPair, sighashReusedValues *consensushashing.SighashReusedValues) ([]byte, error)

RawTxInSignature returns the serialized Schnorr signature for the input idx of the given transaction, with hashType appended to it.

func RawTxInSignatureECDSA

func RawTxInSignatureECDSA(tx *externalapi.DomainTransaction, idx int, hashType consensushashing.SigHashType,
	key *secp256k1.ECDSAPrivateKey, sighashReusedValues *consensushashing.SighashReusedValues) ([]byte, error)

RawTxInSignatureECDSA returns the serialized ECDSA signature for the input idx of the given transaction, with hashType appended to it.

func SignTxOutput

func SignTxOutput(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction, idx int,
	scriptPublicKey *externalapi.ScriptPublicKey, hashType consensushashing.SigHashType,
	sighashReusedValues *consensushashing.SighashReusedValues, kdb KeyDB, sdb ScriptDB,
	previousScript *externalapi.ScriptPublicKey) ([]byte, error)

SignTxOutput signs output idx of the given tx to resolve the script given in scriptPublicKey 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 SignatureScript

func SignatureScript(tx *externalapi.DomainTransaction, idx int, hashType consensushashing.SigHashType,
	privKey *secp256k1.SchnorrKeyPair, sighashReusedValues *consensushashing.SighashReusedValues) ([]byte, error)

SignatureScript creates an input signature script for tx to spend KODA sent from a previous output to the owner of a Schnorr private key. 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. script is the ScriptPublicKey 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 SignatureScriptECDSA

func SignatureScriptECDSA(tx *externalapi.DomainTransaction, idx int, hashType consensushashing.SigHashType,
	privKey *secp256k1.ECDSAPrivateKey, sighashReusedValues *consensushashing.SighashReusedValues) ([]byte, error)

SignatureScriptECDSA creates an input signature script for tx to spend KODA sent from a previous output to the owner of an ECDSA private key. 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. script is the ScriptPublicKey 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.

Types

type AtomicSwapDataPushes

type AtomicSwapDataPushes struct {
	RecipientBlake3 [32]byte
	RefundBlake3    [32]byte
	SecretHash      [32]byte
	SecretSize      int64
	LockTime        uint64
}

AtomicSwapDataPushes houses the data pushes found in atomic swap contracts.

func ExtractAtomicSwapDataPushes

func ExtractAtomicSwapDataPushes(version uint16, scriptPubKey []byte) (*AtomicSwapDataPushes, error)

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.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the virtual machine that executes scripts.

func NewEngine

func NewEngine(scriptPubKey *externalapi.ScriptPublicKey, tx *externalapi.DomainTransaction, txIdx int, flags ScriptFlags,
	sigCache *SigCache, sigCacheECDSA *SigCacheECDSA, sighashReusedValues *consensushashing.SighashReusedValues) (*Engine, error)

NewEngine returns a new script engine for the provided public key script, transaction, and input index. The flags modify the behavior of the script engine according to the description provided by each flag.

func (*Engine) CheckErrorCondition

func (vm *Engine) CheckErrorCondition(finalScript bool) error

CheckErrorCondition returns nil if the running script has ended and was successful, leaving a a true boolean on the stack. An error otherwise, including if the script has not finished.

func (*Engine) DisasmPC

func (vm *Engine) DisasmPC() (string, error)

DisasmPC returns the string for the disassembly of the opcode that will be next to execute when Step() is called.

func (*Engine) DisasmScript

func (vm *Engine) DisasmScript(idx int) (string, error)

DisasmScript returns the disassembly string for the script at the requested offset index. Index 0 is the signature script and 1 is the public key script.

func (*Engine) Execute

func (vm *Engine) Execute() (err error)

Execute will execute all scripts in the script engine and return either nil for successful validation or an error if one occurred.

func (*Engine) GetAltStack

func (vm *Engine) GetAltStack() [][]byte

GetAltStack returns the contents of the alternate stack as an array where the last item in the array is the top of the stack.

func (*Engine) GetStack

func (vm *Engine) GetStack() [][]byte

GetStack returns the contents of the primary stack as an array. where the last item in the array is the top of the stack.

func (*Engine) SetAltStack

func (vm *Engine) SetAltStack(data [][]byte)

SetAltStack sets the contents of the alternate stack to the contents of the provided array where the last item in the array will be the top of the stack.

func (*Engine) SetStack

func (vm *Engine) SetStack(data [][]byte)

SetStack sets the contents of the primary stack to the contents of the provided array where the last item in the array will be the top of the stack.

func (*Engine) Step

func (vm *Engine) Step() (done bool, err error)

Step will execute the next instruction and move the program counter to the next opcode in the script, or the next script if the current has ended. Step will return true in the case that the last opcode was successfully executed.

The result of calling Step or any other method is undefined if an error is returned.

type ErrScriptNotCanonical

type ErrScriptNotCanonical string

ErrScriptNotCanonical identifies a non-canonical script. The caller can use a type assertion to detect this error type.

func (ErrScriptNotCanonical) Error

func (e ErrScriptNotCanonical) Error() string

Error implements the error interface.

type Error

type Error struct {
	ErrorCode   ErrorCode
	Description string
}

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.

func (Error) Error

func (e Error) Error() string

Error satisfies the error interface and prints human-readable errors.

type ErrorCode

type ErrorCode int

ErrorCode identifies a kind of script 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

	// 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 util.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

	// 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

	// 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

	// 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

	// 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

	// ErrMinimalData is returned when 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

	// ErrSigLength is returned when Schnorr signature is of incorrect length
	ErrSigLength

	// 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.
	ErrNotPushOnly

	// ErrPubKeyFormat is returned when the script contains invalid public keys.
	// A valid pubkey should be in uncompressed format as a 64 byte string prefixed with 0x04,
	// or to be in compressed format as a 32 byte string prefixed with 0x02 or 0x03 to signal oddness.
	ErrPubKeyFormat

	// ErrCleanStack is returned when after evaluation, the stack
	// contains more than one element.
	ErrCleanStack

	// ErrNullFail is returned when signatures are not empty
	// on failed checksig or checkmultisig operations.
	ErrNullFail

	// 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 the operand of an OP_IF/OP_NOTIF
	// is not either an empty vector or [0x01].
	ErrMinimalIf
)

These constants are used to identify a specific Error.

func (ErrorCode) String

func (e ErrorCode) String() string

String returns the ErrorCode as a human-readable name.

type KeyClosure

type KeyClosure func(util.Address) (*secp256k1.SchnorrKeyPair, error)

KeyClosure implements KeyDB with a closure.

func (KeyClosure) GetKey

func (kc KeyClosure) GetKey(address util.Address) (*secp256k1.SchnorrKeyPair, error)

GetKey implements KeyDB by returning the result of calling the closure.

type KeyDB

type KeyDB interface {
	GetKey(util.Address) (*secp256k1.SchnorrKeyPair, error)
}

KeyDB is an interface type provided to SignTxOutput, it encapsulates any user state required to get the private keys for an address.

type ScriptBuilder

type ScriptBuilder struct {
	// contains filtered or unexported fields
}

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)

func NewScriptBuilder

func NewScriptBuilder() *ScriptBuilder

NewScriptBuilder returns a new instance of a script builder. See ScriptBuilder for details.

func (*ScriptBuilder) AddData

func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder

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 (*ScriptBuilder) AddFullData

func (b *ScriptBuilder) AddFullData(data []byte) *ScriptBuilder

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 tests where sizes are intentionally made larger than allowed.

Use AddData instead.

func (*ScriptBuilder) AddInt64

func (b *ScriptBuilder) AddInt64(val int64) *ScriptBuilder

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 (*ScriptBuilder) AddLockTimeNumber

func (b *ScriptBuilder) AddLockTimeNumber(lockTime uint64) *ScriptBuilder

AddLockTimeNumber gets a uint64 lockTime,converts it to byte array in little-endian, and then used the AddData function.

func (*ScriptBuilder) AddOp

func (b *ScriptBuilder) AddOp(opcode byte) *ScriptBuilder

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 (*ScriptBuilder) AddOps

func (b *ScriptBuilder) AddOps(opcodes []byte) *ScriptBuilder

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 (*ScriptBuilder) AddSequenceNumber

func (b *ScriptBuilder) AddSequenceNumber(sequence uint64) *ScriptBuilder

AddSequenceNumber gets a uint64 sequence, converts it to byte array in little-endian, and then used the AddData function.

func (*ScriptBuilder) Reset

func (b *ScriptBuilder) Reset() *ScriptBuilder

Reset resets the script so it has no content.

func (*ScriptBuilder) Script

func (b *ScriptBuilder) Script() ([]byte, error)

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.

type ScriptClass

type ScriptClass byte

ScriptClass is an enumeration for the list of standard types of script.

const (
	NonStandardTy ScriptClass = iota // None of the recognized forms.
	PubKeyTy                         // Pay to pubkey.
	PubKeyECDSATy                    // Pay to pubkey ECDSA.
	ScriptHashTy                     // Pay to script hash.
)

Classes of script payment known about in the blockDAG.

func ExtractScriptPubKeyAddress

func ExtractScriptPubKeyAddress(scriptPubKey *externalapi.ScriptPublicKey, dagParams *dagconfig.Params) (ScriptClass, util.Address, error)

ExtractScriptPubKeyAddress returns the type of script and its addresses. Note that it only works for 'standard' transaction script types. Any data such as public keys which are invalid will return a nil address.

Example

This example demonstrates extracting information from a standard public key script.

package main

import (
	"encoding/hex"
	"fmt"

	"github.com/kobradag/kobrad/domain/consensus/model/externalapi"

	"github.com/kobradag/kobrad/domain/consensus/utils/txscript"
	"github.com/kobradag/kobrad/domain/dagconfig"
)

func main() {
	// Start with a standard pay-to-pubkey script.
	scriptHex := "2089ac24ea10bb751af4939623ccc5e550d96842b64e8fca0f63e94b4373fd555eac"
	script, err := hex.DecodeString(scriptHex)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Extract and print details from the script.
	scriptClass, address, err := txscript.ExtractScriptPubKeyAddress(
		&externalapi.ScriptPublicKey{
			Script:  script,
			Version: 0,
		}, &dagconfig.MainnetParams)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Script Class:", scriptClass)
	fmt.Println("Address:", address)

}
Output:

Script Class: pubkey
Address: kobra:qzy6cf82zzah2xh5jwtz8nx9u4gdj6zzke8gljs0v055ksmnl424uyf26y6h8

func GetScriptClass

func GetScriptClass(script []byte) ScriptClass

GetScriptClass returns the class of the script passed.

NonStandardTy will be returned when the script does not parse.

func (ScriptClass) String

func (t ScriptClass) String() string

String implements the Stringer interface by returning the name of the enum script class. If the enum is invalid then "Invalid" will be returned.

type ScriptClosure

type ScriptClosure func(util.Address) ([]byte, error)

ScriptClosure implements ScriptDB with a closure.

func (ScriptClosure) GetScript

func (sc ScriptClosure) GetScript(address util.Address) ([]byte, error)

GetScript implements ScriptDB by returning the result of calling the closure.

type ScriptDB

type ScriptDB interface {
	GetScript(util.Address) ([]byte, error)
}

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 ScriptFlags

type ScriptFlags uint32

ScriptFlags is a bitmask defining additional operations or tests that will be done when executing a script pair.

const (
	// ScriptNoFlags is used when you want to use ScriptFlags without raising any flags
	ScriptNoFlags ScriptFlags = 0
)

type ScriptInfo

type ScriptInfo struct {
	// ScriptPubKeyClass is the class of the public key script and is equivalent
	// to calling GetScriptClass on it.
	ScriptPubKeyClass 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
}

ScriptInfo houses information about a script pair that is determined by CalcScriptInfo.

func CalcScriptInfo

func CalcScriptInfo(sigScript, scriptPubKey []byte, isP2SH bool) (*ScriptInfo, error)

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 scriptPubKey is not a push-only script

type SigCache

type SigCache struct {
	// contains filtered or unexported fields
}

SigCache implements an Schnorr 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.

func NewSigCache

func NewSigCache(maxEntries uint) *SigCache

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 (*SigCache) Add

func (s *SigCache) Add(sigHash secp256k1.Hash, sig *secp256k1.SchnorrSignature, pubKey *secp256k1.SchnorrPublicKey)

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 (*SigCache) Exists

func (s *SigCache) Exists(sigHash secp256k1.Hash, sig *secp256k1.SchnorrSignature, pubKey *secp256k1.SchnorrPublicKey) bool

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.

type SigCacheECDSA

type SigCacheECDSA struct {
	// contains filtered or unexported fields
}

SigCacheECDSA 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.

func NewSigCacheECDSA

func NewSigCacheECDSA(maxEntries uint) *SigCacheECDSA

NewSigCacheECDSA 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 (*SigCacheECDSA) Add

func (s *SigCacheECDSA) Add(sigHash secp256k1.Hash, sig *secp256k1.ECDSASignature, pubKey *secp256k1.ECDSAPublicKey)

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 (*SigCacheECDSA) Exists

func (s *SigCacheECDSA) Exists(sigHash secp256k1.Hash, sig *secp256k1.ECDSASignature, pubKey *secp256k1.ECDSAPublicKey) bool

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL